home *** CD-ROM | disk | FTP | other *** search
/ ftp.mactech.com 2010 / ftp.mactech.com.tar / ftp.mactech.com / machack / Hacks97 / FinderDungeon.sit / Finder Dungeon / source code / DungeonE.c < prev    next >
Text File  |  1997-06-28  |  70KB  |  2,661 lines

  1.  
  2. /*DungeonE – prototype game example for the Mac Game book*/
  3. /*By Ingemar Ragnemalm 1995*/
  4. /**/
  5. /*This game is somewhat similar to MemoryGame, in that it uses a grid, represented*/
  6. /*by an array. The game is a typical (though extremely simplified) dungeon-digging game,*/
  7. /*where the objective is to collect treasures and fight monsters.*/
  8.  
  9. /*Representation:*/
  10. /*The array tileArr holds nearly all information we need. telling what is in each space in the grid.*/
  11. /*Monsters and treasures are only represented this way. In a real game, you may wish to*/
  12. /*keep a list of all monster and treasure positions, to avoid scanning for them and to keep more*/
  13. /*information about each.*/
  14. /*The game also keeps an array that tells what spaces are known to the player (tilesKnown), and*/
  15. /*the player position (playerPosition), so we don't have to scan for it all the time.*/
  16. /*The combat system is extremely simple. If you try moving to an enemy, you have 60% chance to*/
  17. /*hit it and kill it. If an enemy tries to move to you, it has 50% chance to hit, reducing your hit points*/
  18. /*by one.*/
  19. /**/
  20. /*The program ends when we select "Quit".*/
  21.  
  22.  
  23. #include <Sound.h>
  24. #include "MoreFilesExtras.h"
  25. #include "Icons.h"
  26. #include "ScriptableFinder.h"
  27. #include "FullPath.h"
  28. #include <Controls.h>
  29.  
  30. /*Size of the array*/
  31. #define    kArraySizeH 45
  32. #define    kArraySizeV 20
  33.  
  34. short    kWindowSizeH = 24;
  35. short    kWindowSizeV = 16;
  36.  
  37. /*Size of the tiles*/
  38. #define    kTileSizeH 32
  39. #define    kTileSizeV 32
  40.  
  41.  
  42. /*Number of extra pixels below game graphics*/
  43. #define    kScoreFieldHeight    15
  44. /*Base line for text, how far from bottom of window*/
  45. #define    kScoreBaseLine    3
  46.  
  47.  
  48. /*Menu ids*/
  49. #define    appleID 127
  50. #define    fileID 128
  51.  
  52. /* A macro for taking the abs of a value */
  53. #define abs(x) (x>0?x:-x)
  54.  
  55. /* All the possible states of a tile (space in the dungeon) */
  56. //typedef enum {empty, wall, player, enemy, tempEnemy, gold, exitPos} TileState;
  57. typedef enum {empty, wall, fakeWall, exitPos, file, folder, app} TileState;
  58.  
  59. short    levelVRefNum = -1;
  60. long    levelParId = 1;
  61.  
  62. /*The score is a global*/
  63. long gGold, gExperience;
  64.  
  65.  
  66. /* The window pointer */
  67. WindowPtr myWindow = nil;
  68. WindowPtr invWindow = nil;
  69. /* Arrays describing the dungeon */
  70.  
  71. /* What tiles have we seen? */
  72. Boolean tileKnown[kArraySizeH][kArraySizeV];
  73. /* What does each tile contain? */
  74. /* tileArray now only holds static objects */
  75. TileState tileArray[kArraySizeH][kArraySizeV];
  76.  
  77. /*Variables describing the player:*/
  78. //Point playerPosition; -> player->position
  79. short playerHitPoints = 10; // NOT -> player->value
  80.  
  81. /* A boolean telling if we should quit yet or not */
  82. Boolean gDone = false;
  83. Rect    gGameRect;
  84.  
  85. /*Pictures*/
  86. PicHandle floorTile;
  87. PicHandle wallTile;
  88. PicHandle exitTile;
  89. PicHandle playerTile;
  90. PicHandle enemyTile;
  91. PicHandle goldTile;
  92. PicHandle fileTile;
  93. PicHandle folderTile;
  94. PicHandle appTile;
  95. PicHandle deadPlayer;
  96.  
  97. /*All 8 directions as vectors*/
  98. Point directionTable[8] = { { 0, 1 },
  99.                           {-1, 1 },
  100.                           {-1, 0 },
  101.                           {-1,-1 },
  102.                           { 0,-1 },
  103.                           { 1,-1 },
  104.                           { 1, 0 },
  105.                           { 1, 1 }};
  106.  
  107. ControlHandle    scrollH;
  108. ControlHandle    scrollV;
  109.  
  110. OSErr    HFS_ReadCatIndex(                            // read an indexed catalog entry
  111.                 SInt16 pVolume,                        // the volume
  112.                 SInt32 pDirectory,                    // the directory
  113.                 SInt32 pIndex,                        // the index
  114.                 CInfoPBRec *rCatInfo,                // returns the data
  115.                 unsigned char *rName,                // returns the name
  116.                 Boolean *rEndOfCatalog);                // returns end of catalog
  117.  
  118. OSErr    ReadFSSpecIndex(                        // read an indexed FSSpec entry
  119.                 SInt16 pVolume,                        // the volume
  120.                 SInt32 pDirectory,                    // the directory
  121.                 SInt32 pIndex,                        // the index
  122.                 FSSpec *rFSSpec,                    // returns the FSSpec
  123.                 Boolean *rEndOfCatalog);                // returns end of catalog
  124.  
  125. pascal    OSErr    GetFDFlags(short vRefNum,
  126.                               long dirID,
  127.                               ConstStr255Param name,
  128.                               Boolean    *getBits,
  129.                               unsigned short flagBits);
  130. OSErr LaunchApplicationWithDocument(const FSSpec * applicationFSSpecPtr,
  131.     FSSpecArrayHandle fah);
  132.  
  133. OSErr FindAProcess(OSType typeToFind, OSType creatorToFind, ProcessSerialNumberPtr processSN,ProcessInfoRecPtr infoRecToFill);
  134.  
  135. static Boolean    GetIndVRefNum(short which, short *vRefNum, StringPtr    name);
  136. pascal OSErr ResolveAliasFileMountOption(FSSpec *fileFSSpec,
  137.                                                  Boolean resolveAliasChains,
  138.                                                  Boolean *targetIsFolder,
  139.                                                  Boolean *wasAliased,
  140.                                                  Boolean mountRemoteVols);
  141.  
  142. void PlaySoundAsync(StringPtr soundName);
  143. static OSErr    FSpGetIcon(FSSpec *spec, Handle *iconSuite);
  144. static void SendODOCToProcess(ProcessSerialNumberPtr psn, FSSpecArrayHandle fah);
  145. static void DoUpdate();
  146.  
  147. /************************************************/
  148. /* Types and variables for game entity handling */
  149. /************************************************/
  150.  
  151. /* All the possible kinds of game entities */
  152. typedef enum {playerEntity, enemyEntity, goldEntity, fileEntity, directoryEntity, applicationEntity} EntityType;
  153.  
  154. /*Variables describing a game entity*/
  155. typedef struct GameEntityRecord {
  156.     EntityType        kind;                    /* What kind of entity? */
  157.     Point            position;                /* Where in the grid? */
  158.     short            value;                    /* Hit points or point value */
  159.     FSSpec            spec;                    /* name of file or directory */
  160.     OSType            fileType;
  161.     Handle            iconSuite;                /* icon Suite */
  162.     struct GameEntityRecord    *standingOnEntityItem;    /* what item is this entity on top of at the moment? */
  163.     struct GameEntityRecord    *previous, *next;    /* Next and previous entity in the list */
  164. } GameEntityRecord;
  165.  
  166. typedef GameEntityRecord *GameEntityPtr;        /* Define a handle type to it */
  167.  
  168. /* A global pointer is the root of the entity list */
  169. GameEntityPtr    gEntityList = nil;
  170.  
  171. /* The player entity must be easily accessible */
  172. GameEntityPtr    player;
  173.  
  174. /* tileArray now only holds static objects */
  175. /* What entity is in each tile? */
  176. GameEntityPtr entityArray[kArraySizeH][kArraySizeV];
  177.  
  178. GameEntityPtr    playerEntityItem = nil;
  179. /*** End of game entity handling types and variables ***/
  180.  
  181.  
  182. typedef struct HeldItemRecord {
  183.     EntityType        kind;                    /* What kind of entity? */
  184.     FSSpec            spec;
  185.     Handle            iconSuite;
  186.     struct HeldItemRecord    *previous, *next;    /* Next and previous item in the list */
  187. } HeldItemRecord;
  188. typedef HeldItemRecord *HeldItemPtr;        /* Define a handle type to it */
  189.  
  190. HeldItemPtr    heldItemsList = nil;
  191.  
  192.  
  193. static void ClipToGameArea()
  194. {
  195.     Rect    clip;
  196.  
  197.     SetPort(myWindow);
  198.     clip = myWindow->portRect;
  199.     clip.right -= 15;
  200.     clip.bottom -= 15+ kScoreFieldHeight;
  201.     ClipRect(&clip);        
  202. }
  203.  
  204. static void UnclipToGameArea()
  205. {
  206.     Rect    clip = {-32000, -32000, 32000, 32000};
  207.         
  208.     SetPort(myWindow);
  209.     ClipRect(&clip);
  210. }
  211.  
  212.  
  213. #define kScrollBuffer    5
  214. static void ScrollIntoView(Point pt)
  215. {
  216.     short     vScroll, hScroll;
  217.     short    hDelta = 0, vDelta = 0;
  218.     
  219.     vScroll = GetControlValue(scrollV);
  220.     hScroll = GetControlValue(scrollH);
  221.     
  222.     if( pt.h < hScroll)
  223.     {
  224.         hDelta = -(hScroll - pt.h + kScrollBuffer);
  225.     }
  226.     
  227.     if( pt.h > hScroll + kWindowSizeH -1)
  228.     {
  229.         hDelta = (pt.h - (hScroll + kWindowSizeH)) + kScrollBuffer;
  230.     }
  231.     
  232.     if( pt.v < vScroll)
  233.     {
  234.         vDelta = -(vScroll - (pt.v + kScrollBuffer));
  235.     }
  236.     
  237.     if( pt.v > vScroll + kWindowSizeV - 1)
  238.     {
  239.         vDelta = (pt.v - (vScroll + kWindowSizeV)) + kScrollBuffer;
  240.     }
  241.     
  242.     if(hDelta || vDelta)
  243.     {
  244.         SetControlValue(scrollV, vScroll + vDelta);
  245.         SetControlValue(scrollH, hScroll + hDelta);
  246.         
  247.         InvalRect(&myWindow->portRect);
  248.         DoUpdate();
  249.     }
  250.     
  251. }
  252. /* A function that generates a value in the interval 0..range-1 */
  253.  
  254. static short Rand(short range)
  255. {
  256.     return (Random () & 0x7fff) % range;
  257. }; /*Rand*/
  258.  
  259. /* Draw a tile */
  260.  
  261. static void DrawTile(short h, short v)
  262. {
  263.     Rect tileRectangle, boardRect;
  264.     short    scV, scH;
  265.     
  266.     SetRect(&tileRectangle, h * kTileSizeH, v * kTileSizeV, (h + 1) * kTileSizeH, (v + 1) * kTileSizeV);
  267.     
  268.     boardRect = gGameRect;
  269.     
  270.     boardRect.bottom -= kScoreFieldHeight;
  271.     
  272.     scV = GetControlValue(scrollV);
  273.     scH = GetControlValue(scrollH);
  274.     
  275.     SetOrigin(scH * kTileSizeH, scV * kTileSizeV);
  276.     
  277.     ClipToGameArea();
  278.  
  279.     if(!RectInRgn(&tileRectangle, myWindow->visRgn)) 
  280.     {
  281.         SetOrigin(0,0);
  282.         return;
  283.     }
  284.     if ( tileKnown[h][v] )
  285.     {
  286.         switch ( tileArray[h][v] )
  287.         {
  288.             case empty: 
  289.                 DrawPicture(floorTile, &tileRectangle);
  290.                 break;
  291.             case wall: 
  292.                 DrawPicture(wallTile, &tileRectangle);
  293.                 break;
  294.             case fakeWall:
  295.                 DrawPicture(wallTile, &tileRectangle);
  296.                 break;
  297.             case exitPos: 
  298.                 DrawPicture(exitTile, &tileRectangle);
  299.                 break;
  300.             case app:
  301.                 if(entityArray[h][v] && entityArray[h][v]->iconSuite)
  302.                 {
  303.                     DrawPicture(floorTile, &tileRectangle);
  304.                     PlotIconSuite(&tileRectangle,atVerticalCenter | atHorizontalCenter,ttNone,entityArray[h][v]->iconSuite);
  305.                 }
  306.                 else
  307.                     DrawPicture(appTile, &tileRectangle);
  308.                 break;
  309.             case folder:
  310.                 if(entityArray[h][v] && entityArray[h][v]->iconSuite)
  311.                 {
  312.                     DrawPicture(floorTile, &tileRectangle);
  313.                     PlotIconSuite(&tileRectangle,atVerticalCenter | atHorizontalCenter,ttNone,entityArray[h][v]->iconSuite);
  314.                 }
  315.                 else
  316.                     DrawPicture(folderTile, &tileRectangle); 
  317.                 break;
  318.             case file:
  319.                 if(entityArray[h][v] && entityArray[h][v]->iconSuite)
  320.                 {
  321.                     DrawPicture(floorTile, &tileRectangle);
  322.                     PlotIconSuite(&tileRectangle,atVerticalCenter | atHorizontalCenter,ttNone,entityArray[h][v]->iconSuite);
  323.                 }
  324.                 else
  325.                     DrawPicture(fileTile, &tileRectangle); 
  326.                 break;
  327.                 
  328.             default:
  329.                 PaintRect(&tileRectangle);
  330.         }
  331.         if (entityArray[h][v] != nil)
  332.             switch (entityArray[h][v]->kind)
  333.             {
  334.                 case playerEntity:
  335.                     if(playerHitPoints > 0)
  336.                         DrawPicture(playerTile, &tileRectangle);
  337.                     else
  338.                         DrawPicture(deadPlayer, &tileRectangle);
  339.                     break;
  340.                 case enemyEntity:
  341.                     DrawPicture(enemyTile, &tileRectangle);
  342.                     break;
  343.                 case goldEntity:
  344.                     DrawPicture(goldTile, &tileRectangle);
  345.                     break;
  346.                 case applicationEntity:
  347.                     if(entityArray[h][v]->iconSuite)
  348.                     {
  349.                         DrawPicture(floorTile, &tileRectangle);
  350.                         PlotIconSuite(&tileRectangle,atVerticalCenter | atHorizontalCenter,ttNone,entityArray[h][v]->iconSuite);
  351.                     }
  352.                     else
  353.                         DrawPicture(appTile, &tileRectangle);
  354.                     break;
  355.                 case directoryEntity:
  356.                     if(entityArray[h][v]->iconSuite)
  357.                     {
  358.                         DrawPicture(floorTile, &tileRectangle);
  359.                         PlotIconSuite(&tileRectangle,atVerticalCenter | atHorizontalCenter,ttNone,entityArray[h][v]->iconSuite);
  360.                     }
  361.                     else
  362.                         DrawPicture(folderTile, &tileRectangle);
  363.                     break;
  364.                 case fileEntity:
  365.                     if(entityArray[h][v]->iconSuite)
  366.                     {
  367.                         DrawPicture(floorTile, &tileRectangle);
  368.                         PlotIconSuite(&tileRectangle,atVerticalCenter | atHorizontalCenter,ttNone,entityArray[h][v]->iconSuite);
  369.                     }
  370.                     else
  371.                         DrawPicture(fileTile, &tileRectangle);
  372.                     break;
  373.                 default:
  374.                     ;
  375.             }
  376.     }
  377.     else
  378.         PaintRect(&tileRectangle);
  379.  
  380.     UnclipToGameArea();
  381.  
  382.     SetOrigin(0,0);
  383. } /*DrawTile*/
  384.  
  385. static void ShowAll(void)
  386. {
  387.     short i, j;
  388.     for(i = 0; i < kArraySizeH; i++)
  389.         for(j = 0; j < kArraySizeV; j++)
  390.         {
  391.             tileKnown[i][j] = true;
  392.         }    
  393.     InvalRect(&gGameRect);
  394.     DoUpdate();    
  395. }
  396.  
  397. static void InvalInventory()
  398. {    
  399.     GrafPtr savePort;
  400.     
  401.     GetPort(&savePort);
  402.     SetPort(invWindow);
  403.     InvalRect(&invWindow->portRect);
  404.     SetPort(savePort);
  405. }
  406.  
  407.  
  408. /* NewEntity allocates space for a new entity and puts it in the entity list */
  409. static HeldItemPtr NewHeldItem()
  410. {
  411.     HeldItemPtr    newEntity;
  412.  
  413.     newEntity = (HeldItemPtr) NewPtr(sizeof(HeldItemRecord));
  414.     if (newEntity == nil) return nil;
  415.     if (heldItemsList != nil)
  416.     {
  417.         heldItemsList->previous = newEntity;
  418.     }
  419.     newEntity->next = heldItemsList;
  420.     newEntity->previous = nil;
  421.     heldItemsList = newEntity;
  422.     InvalInventory();
  423.     return newEntity;
  424. } /*NewEntity*/
  425.  
  426. /* MakeEntity builds an entity with the given values and puts it into the entityArray */
  427. static HeldItemPtr PickUpItem(GameEntityPtr    item)
  428. {
  429.     HeldItemPtr newEntity;
  430.  
  431.     if(item->kind == fileEntity ||item->kind == directoryEntity ||item->kind == applicationEntity)
  432.     {
  433.         newEntity = NewHeldItem();
  434.         if (newEntity == nil) return nil;
  435.  
  436.         newEntity->kind = item->kind;
  437.         newEntity->iconSuite = nil;
  438.         FSpGetIcon(&item->spec, &newEntity->iconSuite);
  439.         newEntity->spec = item->spec;
  440.     }
  441.  
  442.     return newEntity;
  443. } /*PickUpItem*/
  444.  
  445. static void OpenItem(GameEntityPtr    item)
  446. {
  447.     if(item)
  448.     {
  449.         FSSpecArrayHandle    fah = (FSSpecArrayHandle)NewHandle(0);
  450.  
  451.         AddToFSSpecArrayHandle(&item->spec, fah);
  452.         
  453.         OpenScriptableFinderSelection (fah, false, kAENoReply, nil);
  454.         DisposeHandle((Handle)fah);
  455.         
  456.         if(item->kind == directoryEntity)
  457.         {
  458.             ProcessSerialNumber processSN;
  459.             ProcessInfoRecPtr    info;
  460.             
  461.             if(FindAProcess('FNDR', 'MACS', &processSN,nil) == noErr)
  462.             {
  463.                 SetFrontProcess(&processSN);
  464.             }
  465.         }
  466.     }
  467. }
  468. /* DisposeEntity removes an entity from the list and disposes it. */
  469. static void DisposeHeldItem(HeldItemPtr doomedEntity)
  470. {
  471.     if (doomedEntity == nil) return;
  472.     if (doomedEntity->next != nil)
  473.         doomedEntity->next->previous = doomedEntity->previous;
  474.     if (doomedEntity->previous != nil)
  475.         doomedEntity->previous->next = doomedEntity->next;
  476.     if (doomedEntity == heldItemsList)
  477.         heldItemsList = doomedEntity->next;
  478.     if(doomedEntity->iconSuite)
  479.         DisposeIconSuite(doomedEntity->iconSuite, true);
  480.     DisposePtr((Ptr)doomedEntity);
  481.     InvalInventory();
  482. } /*DisposeEntity*/
  483.  
  484.  
  485. /* drop held items on the current item */
  486. static void DropItems(GameEntityPtr    item)
  487. {
  488.     HeldItemPtr newEntity;
  489.  
  490.     if( item == nil)
  491.     {
  492.         FSSpecArrayHandle    fah = (FSSpecArrayHandle)NewHandle(0);
  493.         HeldItemPtr    items;
  494.         
  495.         for(items = heldItemsList; items; items = items->next)
  496.         {
  497.             AddToFSSpecArrayHandle(&items->spec, fah);
  498.         }
  499.         
  500.         OpenScriptableFinderSelection (fah, false, kAENoReply, nil);
  501.         DisposeHandle((Handle)fah);
  502.         return;
  503.     }
  504.  
  505.     if( item->kind == applicationEntity && heldItemsList)
  506.     {
  507.         FSSpecArrayHandle    fah = (FSSpecArrayHandle)NewHandle(0);
  508.         HeldItemPtr    items;
  509.         FSSpec    appSpec;
  510.         ProcessSerialNumber    psn;
  511.         FInfo    fndrInfo;
  512.         
  513.         for(items = heldItemsList; items; items = items->next)
  514.         {
  515.             AddToFSSpecArrayHandle(&items->spec, fah);
  516.         }
  517.         
  518.         appSpec = item->spec;
  519.         
  520.         FSpGetFInfo(&appSpec, &fndrInfo);
  521.         
  522.         if(FindAProcess(fndrInfo.fdType, fndrInfo.fdCreator, &psn,nil) == noErr)
  523.             SendODOCToProcess(&psn, fah);
  524.         else
  525.             LaunchApplicationWithDocument(&appSpec,fah);
  526.         DisposeHandle((Handle)fah);
  527.     
  528.         while (heldItemsList != nil) DisposeHeldItem(heldItemsList);
  529.     }
  530.     
  531.     if(item->kind == directoryEntity)
  532.     {
  533.         
  534.     }
  535. } /*DropItems*/
  536.  
  537. /*************************************/
  538. /* Routines for game entity handling */
  539. /*************************************/
  540.  
  541. /* NewEntity allocates space for a new entity and puts it in the entity list */
  542. static GameEntityPtr NewEntity()
  543. {
  544.     GameEntityPtr    newEntity;
  545.  
  546.     newEntity = (GameEntityPtr) NewPtr(sizeof(GameEntityRecord));
  547.     if (newEntity == nil) return nil;
  548.     if (gEntityList != nil)
  549.     {
  550.         gEntityList->previous = newEntity;
  551.     }
  552.     newEntity->next = gEntityList;
  553.     newEntity->previous = nil;
  554.     newEntity->standingOnEntityItem = nil;
  555.     gEntityList = newEntity;
  556.     return newEntity;
  557. } /*NewEntity*/
  558.  
  559. /* DisposeEntity removes an entity from the list and disposes it. */
  560. static void DisposeEntity(GameEntityPtr doomedEntity)
  561. {
  562.     if (doomedEntity == nil) return;
  563.     if (doomedEntity->next != nil)
  564.         doomedEntity->next->previous = doomedEntity->previous;
  565.     if (doomedEntity->previous != nil)
  566.         doomedEntity->previous->next = doomedEntity->next;
  567.     if (doomedEntity == gEntityList)
  568.         gEntityList = doomedEntity->next;
  569.     if(doomedEntity->iconSuite)
  570.         DisposeIconSuite(doomedEntity->iconSuite, true);
  571.     DisposePtr((Ptr)doomedEntity);
  572. } /*DisposeEntity*/
  573.  
  574. enum {
  575.     GenericFloppy,
  576.     GenericServer,
  577.     GenericCDRom,
  578.     GenericHD,
  579.     GenericRAMDisk,
  580.     IomegaBernoulliDisk
  581. };
  582.  
  583. static short GetFilesVolumeType(short vRefNum) 
  584. {
  585.     DCtlHandle theDCtl;
  586.     StringPtr theDriverName;
  587.     short theType;
  588.     OSErr theError;
  589.     HParamBlockRec pb;
  590.  
  591.     pb.volumeParam.ioVolIndex = 0; /* use vRefNum */
  592.     pb.volumeParam.ioVRefNum = vRefNum;
  593.     pb.volumeParam.ioNamePtr = nil; /* don't care about name */
  594.     theError = PBHGetVInfoSync(&pb);
  595.  
  596.     if (theError == noErr) {
  597.         theDCtl = GetDCtlEntry(pb.volumeParam.ioVDRefNum);
  598.         if (((**theDCtl).dCtlFlags & (1L << 6)) == 1) { /* RAM or ROM */
  599.             /* RAM => dctlDriver is handle */
  600.             theDriverName = (StringPtr)*((Handle)(**theDCtl).dCtlDriver);
  601.        } else {
  602.             /* ROM => dctlDriver is pointer */
  603.             theDriverName = (StringPtr)(**theDCtl).dCtlDriver;
  604.         }
  605.         theDriverName += 18;
  606.         if (EqualString(theDriverName, "\p.Sony", true, true)) {
  607.             theType = GenericFloppy;
  608.         } else if (EqualString(theDriverName, "\p.AFPTranslator", true, 
  609.                 true)) {
  610.             theType = GenericServer;
  611.         } else if (EqualString(theDriverName, "\p.AppleCD", true, 
  612.                 true)) {
  613.             theType = GenericCDRom;
  614.         } else if (EqualString(theDriverName, "\p.EDisk", true, 
  615.                 true)) {
  616.             theType = GenericRAMDisk;
  617.         } else if (EqualString(theDriverName, "\p.SC/IOMEGA3.4", true, 
  618.                 true)) {
  619.             theType = IomegaBernoulliDisk;
  620.         } else {
  621.             theType = GenericHD;
  622.         }
  623.     } else {
  624.         theType = GenericHD;
  625.     }
  626.     return theType;
  627. }
  628.  
  629. static Boolean _GetIconSuiteForTypeCreator(OSType    inCreator, OSType inType, short vRefNum, Handle *outIconSuite)
  630. {
  631.     DTPBRec    dtpb;
  632.     short    dtdbRefNum = 0, i;
  633.     OSErr    err;
  634.     short    resRef, saveResRefNum = CurResFile();
  635.     short     count = 0, numMenuItems;
  636.     Str63    appName;
  637.     Handle    iconData;
  638.     short    volumeType;
  639.     
  640.     if(vRefNum)
  641.     {
  642.         dtpb.ioNamePtr = NULL;
  643.         dtpb.ioVRefNum = vRefNum;
  644.         err = PBDTGetPath(&dtpb);
  645.     }
  646.     else
  647.     {
  648.         dtpb.ioResult = noErr;
  649.     }
  650.         
  651.     if(dtpb.ioResult == noErr)
  652.     {
  653.         dtdbRefNum = dtpb.ioDTRefNum;
  654.         
  655.         volumeType = GetFilesVolumeType(vRefNum);
  656.         
  657.         if(volumeType != GenericServer && volumeType != GenericFloppy )
  658.         {
  659.         
  660.             dtpb.ioCompletion = nil;
  661.             dtpb.ioDTRefNum = dtdbRefNum;
  662.             dtpb.ioNamePtr = appName;
  663.             dtpb.ioIndex = 0;
  664.             dtpb.ioFileCreator = inCreator;
  665.             
  666. //            err = PBDTGetAPPL( &dtpb, FALSE);
  667.             
  668.             if(err == noErr)
  669.             {
  670.                 dtpb.ioFileType = inType;
  671.                 dtpb.ioTagInfo = 0;
  672.             
  673.                 err = NewIconSuite( outIconSuite );
  674.                 
  675.                 if(!err)
  676.                 {
  677.                     iconData = NewHandle(1024);        //space for icl8
  678.                     if(iconData)
  679.                     {
  680.                         HLock(iconData);
  681.                         dtpb.ioDTBuffer = *iconData;
  682.                         dtpb.ioDTReqCount = 1024;
  683.                         dtpb.ioIconType = kLarge8BitIcon;
  684.  
  685.                         err = PBDTGetIconSync(&dtpb);
  686.                         
  687.                         if(err == noErr)
  688.                         {
  689.                             err = AddIconToSuite(iconData,*outIconSuite,'icl8');
  690.                             HUnlock(iconData);
  691.                         }
  692.                         else
  693.                         {
  694.                             DisposeHandle(iconData);
  695.                         }                
  696.                     }
  697.                                     
  698.                     iconData = NewHandle(512);        //space for icl4
  699.                     if(iconData)
  700.                     {
  701.                         HLock(iconData);
  702.                         dtpb.ioDTBuffer = *iconData;
  703.                         dtpb.ioDTReqCount = 512;
  704.                         dtpb.ioIconType = kLarge4BitIcon;
  705.  
  706.                         err = PBDTGetIconSync(&dtpb);
  707.                         
  708.                         if(err == noErr)
  709.                         {
  710.                             err = AddIconToSuite(iconData,*outIconSuite,'icl4');
  711.                             HUnlock(iconData);
  712.                         }
  713.                         else
  714.                         {
  715.                             DisposeHandle(iconData);
  716.                         }                
  717.                     }
  718.                     
  719.  
  720.                     iconData = NewHandle(256);
  721.                     HLock(iconData);
  722.                     if(iconData)
  723.                     {
  724.                         dtpb.ioDTBuffer = *iconData;
  725.                         dtpb.ioDTReqCount = 256;
  726.                         dtpb.ioIconType = kLargeIcon;
  727.  
  728.                         err = PBDTGetIconSync(&dtpb);
  729.                         
  730.                         if(err == noErr)
  731.                         {
  732.                             err = AddIconToSuite(iconData,*outIconSuite,'ICN#');
  733.                             HUnlock(iconData);
  734.                             return true;
  735.                         }
  736.                         else
  737.                         {
  738.                             //if we can't get the 'ICN#', we don't have a mask and can't draw!
  739.                             DisposeHandle(iconData);
  740.                             DisposeIconSuite(*outIconSuite, true);    
  741.                             *outIconSuite = nil;
  742.                         }                
  743.                     }
  744.                 }                    
  745.             }
  746.         }
  747.     }
  748.     return false;
  749. }
  750.  
  751.  
  752. static Boolean FSpGetHasCustomIcon(const FSSpec *spec)
  753. {
  754.     Boolean    result = false;
  755.     OSErr err = GetFDFlags(spec->vRefNum, spec->parID, spec->name, &result, kHasCustomIcon);
  756.  
  757.     return result;
  758. }
  759.  
  760. static OSErr    FSpGetIcon(FSSpec *spec, Handle *iconSuite)
  761. {
  762.     OSErr    err;
  763.     CInfoPBRec pb;
  764.     Str31 tempName;
  765.     OSErr error;
  766.     short realVRefNum, vRefNum;
  767.     long parID, dirID;
  768.     StringPtr    name;
  769.  
  770.     name = spec->name;
  771.     vRefNum = spec->vRefNum;
  772.     dirID = spec->parID;
  773.     
  774.     /* Protection against File Sharing problem */
  775.     if ( (name == NULL) || (name[0] == 0) )
  776.     {
  777.         tempName[0] = 0;
  778.         pb.hFileInfo.ioNamePtr = tempName;
  779.         pb.hFileInfo.ioFDirIndex = -1;    /* use ioDirID */
  780.     }
  781.     else
  782.     {
  783.         pb.hFileInfo.ioNamePtr = (StringPtr)name;
  784.         pb.hFileInfo.ioFDirIndex = 0;    /* use ioNamePtr and ioDirID */
  785.     }
  786.     pb.hFileInfo.ioVRefNum = vRefNum;
  787.     pb.hFileInfo.ioDirID = dirID;
  788.     error = PBGetCatInfoSync(&pb);
  789.     if ( error == noErr )
  790.     {
  791.         if(pb.hFileInfo.ioFlFndrInfo.fdFlags & kHasCustomIcon || pb.hFileInfo.ioFlFndrInfo.fdFlags & kIsAlias || spec->parID == 1)
  792.         {
  793.             err = GetScriptableFinderFileIcon (spec, false, kAEWaitReply, iconSuite);
  794.         }
  795.         else
  796.         {
  797.             //if its a directory, we will just use the generic directory icon
  798.             if(     (pb.hFileInfo.ioFlAttrib & ioDirMask) == 0 )    //its not directory
  799.             {
  800.                 if(_GetIconSuiteForTypeCreator(pb.hFileInfo.ioFlFndrInfo.fdCreator, pb.hFileInfo.ioFlFndrInfo.fdType, vRefNum, iconSuite) == noErr)
  801.                 {
  802.                     //go with the generic
  803.                     *iconSuite = nil;
  804.                 }
  805.             } 
  806.         }
  807.     }
  808.     return err;
  809. }
  810.  
  811. /* MakeEntity builds an entity with the given values and puts it into the entityArray */
  812. static GameEntityPtr MakeEntity(EntityType eType, short hPos, short vPos, short value, FSSpec *spec, OSType fileType)
  813. {
  814.     GameEntityPtr newEntity;
  815.  
  816.     newEntity = NewEntity();
  817.     if (newEntity == nil) return nil;
  818.     newEntity->position.h = hPos;
  819.     newEntity->position.v = vPos;
  820.     newEntity->kind = eType;
  821.     newEntity->value = value;
  822.     newEntity->iconSuite = nil;
  823.     newEntity->fileType = fileType;
  824.     if(spec)
  825.     {
  826.         Handle iconHandle;
  827.         FInfo    fndrInfo;
  828.         OSErr    err;
  829.         
  830.         newEntity->spec = *spec;
  831.         
  832.         err = FSpGetIcon (&newEntity->spec, &newEntity->iconSuite);
  833.     }
  834.     else
  835.         newEntity->spec.name[0] = 0;
  836. /* Border checking here would be good for safety */
  837.     entityArray[newEntity->position.h][newEntity->position.v] = newEntity;
  838. //    DrawTile(newEntity->position.h, newEntity->position.v);
  839.     return newEntity;
  840. } /*MakeEntity*/
  841.  
  842. /* KillEntity disposes an entity, removes it from EntityArray and erases it */
  843. static void KillEntity(GameEntityPtr doomedEntity)
  844. {
  845.     if (doomedEntity == nil) return;
  846.     if (entityArray[doomedEntity->position.h][doomedEntity->position.v] == doomedEntity)
  847.         entityArray[doomedEntity->position.h][doomedEntity->position.v] = nil;
  848.     DrawTile(doomedEntity->position.h, doomedEntity->position.v);
  849.     DisposeEntity(doomedEntity);
  850. } /*KillEntity*/
  851.  
  852. /*** End of game entity handling routines ***/
  853.  
  854. /*** Score handling and display ***/
  855.  
  856. static void DrawScore()
  857. {
  858.     Str255    tempString;
  859.     Rect    blankRect;
  860.     
  861.     SetPort(myWindow);
  862.  
  863.     blankRect = gGameRect;
  864.     blankRect.top = gGameRect.bottom - kScoreFieldHeight;
  865.     EraseRect(&blankRect);
  866.  
  867.     MoveTo(gGameRect.right * 1 / 5, gGameRect.bottom - kScoreBaseLine);
  868.     DrawString("\pGold: ");
  869.     NumToString(gGold, tempString);
  870.     DrawString(tempString);
  871.  
  872.     MoveTo(gGameRect.right * 2 / 5, gGameRect.bottom - kScoreBaseLine);
  873.     DrawString("\pExperience: ");
  874.     NumToString(gExperience, tempString);
  875.     DrawString(tempString);
  876.  
  877.     MoveTo(gGameRect.right * 3 / 5, gGameRect.bottom - kScoreBaseLine);
  878.     DrawString("\pHit points: ");
  879.     NumToString(playerHitPoints, tempString);
  880.     DrawString(tempString);
  881.  
  882.     if(player->standingOnEntityItem)
  883.     {
  884.         TextSize(9);
  885.         TextFace(bold);
  886.         MoveTo(gGameRect.left + 2, gGameRect.bottom - kScoreBaseLine);
  887.         DrawString(player->standingOnEntityItem->spec.name);
  888.     }    
  889.     TextSize(12);
  890.     TextFace(0);
  891.  
  892. } /*DrawScore*/
  893.  
  894.  
  895. static void AddScore(long addToGold, long addToExperience)
  896. {
  897.     gGold += addToGold;
  898.     gExperience += addToExperience;
  899.     DrawScore();
  900. } /*AddScore*/
  901.  
  902.  
  903. #define    kNumHealthTypes 7
  904. OSType healthTypes[kNumHealthTypes] = {'MSIE', 'XCEL', 'PPT3','MSWD', 'PWSC', 'WFOS', 'MSNM'};
  905. static void PayForHealth(void)
  906. {
  907.     short    i;
  908.     if(player->standingOnEntityItem)
  909.     {
  910.         for(i = 0; i < kNumHealthTypes; i++)
  911.         {
  912.             if(player->standingOnEntityItem->fileType == healthTypes[i])
  913.             {
  914.                 if(gGold > 100)
  915.                 {
  916.                     gGold -= 100;
  917.                     playerHitPoints++;
  918.                     DrawScore();
  919.                     PlaySoundAsync("\pBought Health");
  920.                 }
  921.             }
  922.         }
  923.     }
  924. }
  925.  
  926.  
  927. /* Set all tiles around the player to be known, and draw them if they were not known before. */
  928.  
  929. static void ShowAroundPlayer()
  930. {
  931.     short h, v;
  932.  
  933.     ScrollIntoView(player->position);
  934.     for ( h = player->position.h - 1 ; h <= player->position.h + 1 ; h++)
  935.         for ( v = player->position.v - 1 ; v <= player->position.v + 1 ; v++)
  936.             if ( ! tileKnown[h][v] )
  937.             {
  938.                 tileKnown[h][v] = true;
  939.                 DrawTile(h, v);
  940.             }
  941. } /*ShowAroundPlayer*/
  942.  
  943.  
  944. static Boolean    FindRandomEmptySpot(Point *freeSpot, Rect *rooms, short numRooms)
  945. {
  946.     short     i;
  947.     short    room;
  948.     //lets try real randomness for a little while
  949.     for(i = 1; i <= 50; i++)
  950.     {
  951.         freeSpot->v = Rand(kArraySizeV);
  952.         freeSpot->h = Rand(kArraySizeH);
  953.         
  954.         if(entityArray[freeSpot->h][freeSpot->v] == nil && tileArray[freeSpot->h][freeSpot->v] == empty)
  955.             return true;
  956.     }
  957.     
  958.     //if we got here, we still haven't found an empty spot
  959.     //Choose a random room, then look for a spot in it.
  960.     for(i = 1; i <= 50; i++)
  961.     {
  962.         room = Rand(numRooms);
  963.         
  964.         freeSpot->v = rooms[room].top + Rand(rooms[room].bottom - rooms[room].top);
  965.         freeSpot->h = rooms[room].left + Rand(rooms[room].right - rooms[room].left);
  966.  
  967.         if(entityArray[freeSpot->h][freeSpot->v] == nil && tileArray[freeSpot->h][freeSpot->v] == empty)
  968.             return true;
  969.     }
  970.     
  971.     //finally, walk the room list and find the first empty spot
  972.     for(room = 0; room < numRooms; room++)
  973.     {
  974.         for(freeSpot->v = rooms[room].top; freeSpot->v <= rooms[room].bottom; freeSpot->v ++)
  975.         {
  976.             for(freeSpot->h = rooms[room].left; freeSpot->h <= rooms[room].right; freeSpot->h ++)
  977.             {
  978.                 if(entityArray[freeSpot->h][freeSpot->v] == nil && tileArray[freeSpot->h][freeSpot->v] == empty)
  979.                     return true;
  980.             }
  981.         }
  982.  
  983.     }
  984.  
  985.     return false;
  986. }
  987. /* The level generation routine */
  988.  
  989. static void CreateLevel()
  990. {
  991.     Rect roomRect[20];
  992.     short room;
  993.     short height, width;
  994.     short h, v, h1, v1, h2, v2;
  995.     short numRooms;
  996.     short numTreasures, numMonsters;
  997.     short i;
  998.     short fileIndex;
  999.     FSSpec fileSpec;
  1000.     long    freeSpots = 0;
  1001.     short    pathLen;
  1002.     Handle    path;
  1003.     Str255    title;
  1004.     Boolean    done = false;
  1005. /*For each tile position, we set the initial state.*/
  1006. /**/
  1007. /*Here we generate the dungeon randomly, with a rather simple algorithm.*/
  1008. /*Most real games use pre-designed levels, preferrably stored in resources.*/
  1009.  
  1010.  
  1011. /*Dungeon generation algorithm:*/
  1012. /*We select a number of rooms to be placed, 3-10*/
  1013. /*Each room is randomly assigned a size, and then a position.*/
  1014. /*In each room we may put monsters and/or treasures.*/
  1015. /*From each room except the last, we make a path from the room to the next.*/
  1016. /*This guarantees that all rooms are connected.*/
  1017.  
  1018.     SetControlValue(scrollV, 0);
  1019.     SetControlValue(scrollH, 0);
  1020.     
  1021.     if(GetFullPath(levelVRefNum,levelParId,nil,&pathLen,&path) == noErr)
  1022.     {
  1023.         title[0] = (pathLen > 250 ? 250 : pathLen);
  1024.         BlockMoveData(*path, &(title[1]), pathLen);
  1025.         SetWTitle(myWindow, title);
  1026.     }
  1027.     else
  1028.         SetWTitle(myWindow, "\pDrives");
  1029. /*First fill the entire dungeon with walls!*/
  1030.     for ( h = 0 ; h < kArraySizeH ; h++)
  1031.         for ( v = 0 ; v < kArraySizeV ; v++)
  1032.             tileArray[h][v] = wall;
  1033.  
  1034. /*All tiles are unknown when we start*/
  1035. /*This must be in the beginning now, since MakeEntity draws*/
  1036. /*the new entity*/
  1037.     for ( h = 0 ; h < kArraySizeH ; h++)
  1038.         for ( v = 0 ; v < kArraySizeV ; v++)
  1039.             tileKnown[h][v] = false;
  1040.  
  1041. /*Dispose all old entities*/
  1042.     while (gEntityList != nil) DisposeEntity(gEntityList);
  1043.  
  1044. /*Fill the entityArray with nil - there's nobody there!*/
  1045.     for ( h = 0 ; h < kArraySizeH ; h++)
  1046.         for ( v = 0 ; v < kArraySizeV ; v++)
  1047.             entityArray[h][v] = nil;
  1048.  
  1049.     numRooms = 5 + Rand(5); /*5 to 9 rooms*/
  1050.  
  1051. /*Create each room*/
  1052.     for ( room = 0 ; room <= numRooms - 1 ; room++)
  1053.     {
  1054.         height = 1 + Rand(5 - numRooms / 2);
  1055.         width = 1 + Rand(5 - numRooms / 2);
  1056.         roomRect[room].top = 1 + Rand(kArraySizeV - height - 2);
  1057.         roomRect[room].bottom = roomRect[room].top + height;
  1058.         roomRect[room].left = 1 + Rand(kArraySizeH - width - 2);
  1059.         roomRect[room].right = roomRect[room].left + width;
  1060.  
  1061.         for ( h = roomRect[room].left ; h <= roomRect[room].right ; h++)
  1062.             for ( v = roomRect[room].top ; v <= roomRect[room].bottom ; v++)
  1063.             {
  1064.                     tileArray[h][v] = empty;
  1065.                     freeSpots++;
  1066.             }
  1067.     };
  1068.  
  1069. /*Make paths between all rooms*/
  1070.     for ( room = 0 ; room <= numRooms - 2 ; room++)
  1071.     {
  1072. /*We make a path from h1, h2, to h2, v2*/
  1073.         h1 = roomRect[room].left + Rand(roomRect[room].right - roomRect[room].left + 1);
  1074.         v1 = roomRect[room].top + Rand(roomRect[room].bottom - roomRect[room].top + 1);
  1075.         h2 = roomRect[room + 1].left + Rand(roomRect[room + 1].right - roomRect[room + 1].left + 1);
  1076.         v2 = roomRect[room + 1].top + Rand(roomRect[room + 1].bottom - roomRect[room + 1].top + 1);
  1077.  
  1078. /*First move along the h axis*/
  1079.         if ( h1 < h2 )
  1080.             for ( h = h1 ; h <= h2 ; h++)
  1081.             {
  1082.                 if(Rand(10) == 0)
  1083.                 {
  1084.                     tileArray[h][v1] = fakeWall;
  1085.                 }
  1086.                 else
  1087.                 {
  1088.                     tileArray[h][v1] = empty;
  1089.                 }
  1090.                 freeSpots++;
  1091.             }
  1092.         else
  1093.             for ( h = h1 ; h >= h2 ; h--)
  1094.             {
  1095.                 tileArray[h][v1] = empty;
  1096.                 freeSpots++;
  1097.             }
  1098. /*And then along the v axis*/
  1099.         if ( v1 < v2 )
  1100.             for ( v = v1 ; v <= v2 ; v++)
  1101.             {
  1102.                 if(Rand(10) == 0)
  1103.                 {
  1104.                     tileArray[h2][v] = fakeWall;
  1105.                 }
  1106.                 else
  1107.                 {
  1108.                     tileArray[h2][v] = empty;
  1109.                 }
  1110.                 freeSpots++;
  1111.             }
  1112.         else
  1113.             for ( v = v1 ; v >= v2 ; v--)
  1114.             {
  1115.                 tileArray[h2][v] = empty;
  1116.                 freeSpots++;
  1117.             }
  1118.     };
  1119.  
  1120. /*Now populate the rooms!*/
  1121.     for ( room = 1 ; room <= numRooms - 1 ; room++)
  1122.     {
  1123.         numTreasures = Rand(3);        /*0 to 2 treasures*/
  1124.         for ( i = 1 ; i <= numTreasures ; i++)
  1125.         {
  1126.             h = roomRect[room].left + Rand(roomRect[room].right - roomRect[room].left + 1);
  1127.             v = roomRect[room].top + Rand(roomRect[room].bottom - roomRect[room].top + 1);
  1128.             if (entityArray[h][v] == nil)
  1129.                 MakeEntity(goldEntity, h, v, Rand(100) + 1, nil, 'gold');
  1130. //            tileArray[h][v] = gold;
  1131.         };
  1132.         if(Rand(2))
  1133.             numMonsters = Rand(2);        /*0 to 1 monsters*/
  1134.         else
  1135.             numMonsters = 0;
  1136.             
  1137.         for ( i = 1 ; i <= numMonsters; i++)
  1138.         {
  1139.             h = roomRect[room].left + Rand(roomRect[room].right - roomRect[room].left + 1);
  1140.             v = roomRect[room].top + Rand(roomRect[room].bottom - roomRect[room].top + 1);
  1141.             if (entityArray[h][v] == nil)
  1142.                 MakeEntity(enemyEntity, h, v, 2, nil, 'bomb');
  1143. //            tileArray[h][v] = enemy;
  1144.         };
  1145.     };
  1146.  
  1147. /*Finally, place the player in the first room and the exit in the last. Also check that the exit is*/
  1148. /*not the same position as the player! (It can happen, since we don't mak sure that rooms don't*/
  1149. /*overlap!)*/
  1150.  
  1151. /*Player position:*/
  1152.     h = roomRect[0].left + Rand(roomRect[0].right - roomRect[0].left + 1);
  1153.     v = roomRect[0].top + Rand(roomRect[0].bottom - roomRect[0].top + 1);
  1154.     if (entityArray[h][v] != nil)
  1155.         KillEntity(entityArray[h][v]);
  1156.     player = MakeEntity(playerEntity, h, v, 5, nil, 'plyr');
  1157. //    tileArray[h][v] = player;
  1158. /*Exit position:*/
  1159.     h = roomRect[numRooms - 1].left + Rand(roomRect[numRooms - 1].right - roomRect[numRooms - 1].left + 1);
  1160.     v = roomRect[numRooms - 1].top + Rand(roomRect[numRooms - 1].bottom - roomRect[numRooms - 1].top + 1);
  1161. /*But please don't overwrite the player with the exit!*/
  1162.     if ( h == player->position.h )
  1163.         if ( v == player->position.v )
  1164.         {
  1165. /*Try another room:*/
  1166.             h = roomRect[numRooms - 2].left + Rand(roomRect[numRooms - 2].right - roomRect[numRooms - 2].left + 1);
  1167.             v = roomRect[numRooms - 2].top + Rand(roomRect[numRooms - 2].bottom - roomRect[numRooms - 2].top + 1);
  1168.  
  1169. /*Still failure? Darn. Just take a space next to the player.*/
  1170.             if ( h == player->position.h )
  1171.                 if ( v == player->position.v )
  1172.                     if ( h < kArraySizeH )
  1173.                         h = h + 1;
  1174.                     else
  1175.                         h = h - 1;
  1176.         };
  1177. /*OK, that's enough. Set the exit!*/
  1178.     tileArray[h][v] = exitPos;
  1179.  
  1180.     //Place the files
  1181.     for(fileIndex = 1; !done; fileIndex ++)
  1182.     {
  1183.         OSErr    err = noErr;
  1184.         Point    freeSpot;
  1185.         
  1186.         if(levelParId == 1)
  1187.         {
  1188.             fileSpec.parID = 1;
  1189.             done = !GetIndVRefNum(fileIndex, &fileSpec.vRefNum, fileSpec.name);
  1190.         }                
  1191.         else
  1192.             err = ReadFSSpecIndex(levelVRefNum,levelParId,fileIndex,&fileSpec, &done);
  1193.         
  1194.         if(err) done = true;
  1195.         
  1196.         if(!done)
  1197.         {
  1198.             if(FindRandomEmptySpot(&freeSpot, roomRect, numRooms))
  1199.             {
  1200.                 long    newDirId;
  1201.                 Boolean    isDirectory;
  1202.                 FInfo    fndrInfo;
  1203.                 Boolean    wasAlias;
  1204.                 FSpGetFInfo(&fileSpec, &fndrInfo);
  1205.                 
  1206.                 if(fndrInfo.fdFlags & kIsAlias)
  1207.                 {
  1208.                     err = ResolveAliasFileMountOption(&fileSpec,true,&isDirectory,&wasAlias, false);
  1209.                 }
  1210.                 
  1211.                 err = FSpGetDirectoryID(&fileSpec, &newDirId, &isDirectory);
  1212.                 if(isDirectory)
  1213.                 {
  1214.                     MakeEntity(directoryEntity, freeSpot.h, freeSpot.v, 0, &fileSpec, fndrInfo.fdCreator);
  1215.                     tileArray[freeSpot.h][freeSpot.v] = folder;
  1216.                 }
  1217.                 else
  1218.                 if(fndrInfo.fdType == 'APPL')
  1219.                 {
  1220.                     MakeEntity(applicationEntity, freeSpot.h, freeSpot.v, 0, &fileSpec, fndrInfo.fdCreator);
  1221.                     tileArray[freeSpot.h][freeSpot.v] = app;
  1222.                 }            
  1223.                 else
  1224.                 {
  1225.                     MakeEntity(fileEntity, freeSpot.h, freeSpot.v, 0, &fileSpec, fndrInfo.fdCreator);
  1226.                     tileArray[freeSpot.h][freeSpot.v] = file;
  1227.                 }
  1228.                 
  1229.             }
  1230.         }
  1231.     }
  1232.  
  1233. /*All tiles are unknown when we start*/
  1234. /*…except the ones around the player*/
  1235.  
  1236. /*Make the spaces around the player known*/
  1237.     ShowAroundPlayer();
  1238.  
  1239. /*Draw all tiles!*/
  1240.     for ( h = 0 ; h < kArraySizeH ; h++)
  1241.         for ( v = 0 ; v < kArraySizeV ; v++)
  1242.             DrawTile(h, v);
  1243. } /*CreateLevel*/
  1244.  
  1245.  
  1246. /* Move an enemy */
  1247.  
  1248. static void MoveEnemy(GameEntityPtr theEnemy /*short h, short v*/)
  1249. {
  1250.         short dist;
  1251.         short newh, newv;
  1252.         short dir;
  1253.  
  1254.     
  1255. /*1: decide if we are close to enough to the player to "hear" the player*/
  1256.  
  1257.     dist = abs(theEnemy->position.h - player->position.h) + abs(theEnemy->position.v - player->position.v); /*City Block distance*/
  1258.  
  1259. /*2: Make a suggested destination, newh, newv*/
  1260.  
  1261.     if ( dist < Rand(15) )                    /*Move towards the player*/
  1262.     {
  1263.         if ( theEnemy->position.h < player->position.h )
  1264.             newh = theEnemy->position.h + 1;
  1265.         else if ( theEnemy->position.h > player->position.h )
  1266.             newh = theEnemy->position.h - 1;
  1267.         else
  1268.             newh = theEnemy->position.h;
  1269.         if ( theEnemy->position.v < player->position.v )
  1270.             newv = theEnemy->position.v + 1;
  1271.         else if ( theEnemy->position.v > player->position.v )
  1272.             newv = theEnemy->position.v - 1;
  1273.         else
  1274.             newv = theEnemy->position.v;
  1275.     }
  1276.     else                                    /*Move randomly*/
  1277.     { 
  1278.         dir = Rand(8);
  1279.         newh = theEnemy->position.h + directionTable[dir].h;
  1280.         newv = theEnemy->position.v + directionTable[dir].v;
  1281.     }
  1282.  
  1283. /*3: Check what is in the destination and take appropriate action (move, fight)*/
  1284.  
  1285.     switch ( tileArray[newh][newv] )
  1286.     {
  1287.     case empty:
  1288.     case exitPos:
  1289.     case app:
  1290.     case file:
  1291.     case folder:
  1292.     case fakeWall:
  1293. /*                tileArray[newh][newv] = tempEnemy;    /*We can't use "enemy", since then we might process it again in the same move!*/
  1294. /*                tileArray[h][v] = empty;*/
  1295.         if (entityArray[newh][newv] == player)
  1296.         {
  1297.             if ( Rand(10) > 5 )                            /*Does it hit?*/
  1298.             {                                        /*Enemy hits player!*/
  1299.                 playerHitPoints--;                    /*Reduce player hit points*/
  1300.                 DrawScore();                        /*Draw score to display the lower hit points!*/
  1301.                 if ( playerHitPoints > 0 )
  1302.                 {                                        /*Player still lives!*/
  1303.                     if ( noErr != SndPlay(nil, (SndListHandle)GetNamedResource('snd ', "\pPlayer hit"), false) )
  1304.                         ;
  1305.                 }
  1306.                 else
  1307.                 {                                /*Player died!*/
  1308.                     DrawTile(player->position.h, player->position.v);
  1309.                     PlaySoundAsync("\pPlayer died");
  1310.                 };
  1311.             }
  1312.             else
  1313.             {                                    /*Miss!*/
  1314.                 if ( noErr != SndPlay(nil, (SndListHandle)GetNamedResource('snd ', "\pPlayer miss"), false) )
  1315.                     ;
  1316.             }
  1317.         }
  1318.         else
  1319.         if (entityArray[newh][newv] == nil)
  1320.         {
  1321.             if(theEnemy->standingOnEntityItem)
  1322.             {
  1323.                 entityArray[theEnemy->position.h][theEnemy->position.v] = theEnemy->standingOnEntityItem;
  1324.                 theEnemy->standingOnEntityItem = nil;
  1325.             }
  1326.             else
  1327.                 entityArray[theEnemy->position.h][theEnemy->position.v] = nil;
  1328.  
  1329.             entityArray[newh][newv] = theEnemy;
  1330.             DrawTile(newh, newv);
  1331.             DrawTile(theEnemy->position.h, theEnemy->position.v);
  1332.             theEnemy->position.h = newh;
  1333.             theEnemy->position.v = newv;
  1334.         }
  1335.         else
  1336.         {
  1337.             if(theEnemy->standingOnEntityItem)
  1338.             {
  1339.                 entityArray[theEnemy->position.h][theEnemy->position.v] = theEnemy->standingOnEntityItem;
  1340.                 theEnemy->standingOnEntityItem = nil;
  1341.             }
  1342.             else
  1343.                 entityArray[theEnemy->position.h][theEnemy->position.v] = nil;
  1344.                 
  1345.             theEnemy->standingOnEntityItem = entityArray[newh][newv];
  1346.             entityArray[newh][newv] = theEnemy;
  1347.  
  1348.             DrawTile(newh, newv);
  1349.             DrawTile(theEnemy->position.h, theEnemy->position.v);
  1350.             theEnemy->position.h = newh;
  1351.             theEnemy->position.v = newv;
  1352.         }
  1353.         break;
  1354.  
  1355.          case wall:
  1356. //        case enemy:
  1357. //        case gold:
  1358. //        case exitPos:
  1359. //        case tempEnemy: 
  1360.             break;                                            /*Don't move to any of these!*/
  1361.     }; /*case*/
  1362.     
  1363. } /*MoveEnemy*/
  1364.  
  1365.  
  1366. /* Initialize - create window, load graphics */
  1367.  
  1368. static void InitDungeon()
  1369. {
  1370.     Rect windowRectangle;
  1371.     Rect    scrollRect;
  1372. /*Set up the window*/
  1373.     SetRect(&windowRectangle, 30, 30, 250, 200);
  1374.     invWindow = NewCWindow(nil, &windowRectangle, "\pInventory", true, documentProc, (WindowPtr)-1L, false, 0); 
  1375.  
  1376.     SetRect(&windowRectangle, 0, 40, 15 + kWindowSizeH * kTileSizeH, 55 + kWindowSizeV * kTileSizeV + kScoreFieldHeight);
  1377.     myWindow = NewCWindow(nil, &windowRectangle, "\pDrives", true, documentProc, (WindowPtr)-1L, false, 0);
  1378.     SetPort(myWindow);
  1379.  
  1380.     gGameRect = myWindow->portRect;
  1381.     gGameRect.bottom -= 15;
  1382.     gGameRect.right -= 15;
  1383.     
  1384.     scrollRect = myWindow->portRect;
  1385.     scrollRect.left = scrollRect.right - 15;
  1386.     scrollRect.right ++;
  1387.     scrollRect.bottom -= 14;
  1388.     scrollRect.top --;
  1389.     scrollV = NewControl(myWindow,&scrollRect,"\p",true,0,0,kArraySizeV - kWindowSizeV,16,0);
  1390.  
  1391.     scrollRect = myWindow->portRect;
  1392.     scrollRect.top = scrollRect.bottom - 15;
  1393.     scrollRect.bottom ++;
  1394.     scrollRect.right -= 14;
  1395.     scrollRect.left --;
  1396.     scrollH = NewControl(myWindow,&scrollRect,"\p",true,0,0,kArraySizeH - kWindowSizeH,16,0);
  1397.  
  1398.     qd.randSeed = TickCount ();    /*Seed the random number generator*/
  1399.  
  1400. /*Load all pictures*/
  1401.     floorTile = GetPicture(128);            /*PICT resource #128.*/
  1402.     playerTile = GetPicture(129);            /*PICT resource #129.*/
  1403.     enemyTile = GetPicture(130);            /*PICT resource #130.*/
  1404.     goldTile = GetPicture(131);                /*PICT resource #131.*/
  1405.     wallTile = GetPicture(132);                /*PICT resource #132.*/
  1406.     exitTile = GetPicture(133);                /*PICT resource #133.*/
  1407.     fileTile = GetPicture(135); 
  1408.     folderTile = GetPicture(134); 
  1409.     appTile = GetPicture(136);
  1410.     deadPlayer = GetPicture(137); 
  1411. } /*InitDungeon*/
  1412.  
  1413.  
  1414. /* Set up for a new game */
  1415.  
  1416. static void NewGame()
  1417. {
  1418. /* Fill in the tileArr array */
  1419.         CreateLevel();
  1420.  
  1421. /* Start with a healthy player */
  1422.         playerHitPoints = 10;
  1423.         gGold = 0;
  1424.         gExperience = 0;
  1425. } /*NewGame*/
  1426.  
  1427.  
  1428. /* ValidMove checks if a tile clickedTile is inside the array bounds *and* near the player */
  1429.  
  1430. static Boolean ValidMove(Point clickedTile)
  1431. {
  1432. /* Valid tile?*/
  1433.     if ( clickedTile.h >= 0 )
  1434.         if ( clickedTile.v >= 0 )
  1435.             if ( clickedTile.h < kArraySizeH )
  1436.                 if ( clickedTile.v < kArraySizeV )
  1437. /* OK, we are inside the game area, clicking in some space! Is it next to the player?*/
  1438.                     if ( clickedTile.h >= player->position.h - 1 )
  1439.                         if ( clickedTile.h <= player->position.h + 1 )
  1440.                             if ( clickedTile.v >= player->position.v - 1 )
  1441.                                 if ( clickedTile.v <= player->position.v + 1 ) 
  1442.                                     return true;
  1443. /* If that wasn't the case, it wasn't vcalid; return false! */
  1444.     return false;
  1445. } /*ValidMove*/
  1446.  
  1447.  
  1448. /* Try to move the player to the position where we clicked. */
  1449.  
  1450. static void MovePlayer(Point clickedTile)
  1451. {
  1452.     short h, v;
  1453.     GameEntityPtr    theEntity;
  1454.     Boolean        freedOldPlayerSpot = false;
  1455.  
  1456. /* Valid move?*/
  1457.     if (ValidMove(clickedTile))
  1458. /* Yes! What is there? */
  1459.     {
  1460.         ScrollIntoView(clickedTile);
  1461.         if (entityArray[clickedTile.h][clickedTile.v] != nil)
  1462.         {
  1463.             switch (entityArray[clickedTile.h][clickedTile.v]->kind)
  1464.             {
  1465.                 case enemyEntity:
  1466.                     if ( Rand(10) > 4 )
  1467.                     { /*Hit! Play a "monster died" sound*/
  1468.                         
  1469.                         entityArray[clickedTile.h][clickedTile.v]->value--;
  1470.                         if (entityArray[clickedTile.h][clickedTile.v]->value <= 0)
  1471.                         {    /* Monster died! */
  1472.                             GameEntityPtr monster;
  1473.                             PlaySoundAsync("\pEnemy died");
  1474.                             /* Walk to the space where the monster was.*/
  1475.                             /*tileArray[player->position.h][player->position.v] = empty;
  1476.                             tileArray[clickedTile.h][clickedTile.v] = player;*/
  1477.                             
  1478.                             monster = entityArray[clickedTile.h][clickedTile.v];
  1479.                             if(monster->standingOnEntityItem)
  1480.                                 entityArray[clickedTile.h][clickedTile.v] = monster->standingOnEntityItem;
  1481.                             
  1482.                             KillEntity(monster);
  1483.  
  1484.                             if(player->standingOnEntityItem && !freedOldPlayerSpot)
  1485.                             {
  1486.                                 entityArray[player->position.h][player->position.v] = player->standingOnEntityItem;
  1487.                                 player->standingOnEntityItem = nil;
  1488.                             }
  1489.                             else
  1490.                                 entityArray[player->position.h][player->position.v] = nil;
  1491.                             
  1492.                             if(entityArray[clickedTile.h][clickedTile.v] != nil)
  1493.                             {
  1494.                                 player->standingOnEntityItem = entityArray[clickedTile.h][clickedTile.v];
  1495.                             }
  1496.  
  1497.                             entityArray[clickedTile.h][clickedTile.v] = player;
  1498.         
  1499.                             DrawTile(player->position.h, player->position.v);
  1500.                             DrawTile(clickedTile.h, clickedTile.v);
  1501.                             player->position = clickedTile;
  1502.  
  1503. /* Killed a monster! Get experience! Let's say one point for the troll! */
  1504.                             AddScore(0, 1);
  1505.                         }
  1506.                         else    /* Monster still lives! */
  1507.                         {
  1508.                         }
  1509.                     }
  1510.                     else
  1511.                     { /*Miss! Play the "miss" sound. */
  1512.                     if ( noErr != SndPlay(nil, (SndListHandle)GetNamedResource('snd ', "\pEnemy miss"), false) )
  1513.                         ;
  1514.                     }
  1515.                     break;
  1516.                 case goldEntity:
  1517. /* Gold - add score! */
  1518.                     AddScore(entityArray[clickedTile.h][clickedTile.v]->value, 0);
  1519.                     
  1520.                     KillEntity(entityArray[clickedTile.h][clickedTile.v]);
  1521.                     if(player->standingOnEntityItem)
  1522.                     {
  1523.                         entityArray[player->position.h][player->position.v] = player->standingOnEntityItem;
  1524.                         player->standingOnEntityItem = nil;
  1525.                     }
  1526.                     else
  1527.                         entityArray[player->position.h][player->position.v] = nil;
  1528.                     entityArray[clickedTile.h][clickedTile.v] = player;
  1529.     
  1530.                     DrawTile(player->position.h, player->position.v);
  1531.                     DrawTile(clickedTile.h, clickedTile.v);
  1532.                     player->position = clickedTile;
  1533.                     PlaySoundAsync("\pMoney");
  1534.                     break;
  1535.                 case directoryEntity:
  1536.                 case fileEntity:
  1537.                 case applicationEntity:
  1538.                     if(player->standingOnEntityItem)
  1539.                     {
  1540.                         entityArray[player->position.h][player->position.v] = player->standingOnEntityItem;
  1541.                         freedOldPlayerSpot = true;
  1542.                     }
  1543.                     else
  1544.                         entityArray[player->position.h][player->position.v] = nil;
  1545.  
  1546.                     player->standingOnEntityItem = entityArray[clickedTile.h][clickedTile.v];
  1547.                     
  1548.                 
  1549.                     entityArray[clickedTile.h][clickedTile.v] = player;
  1550.                     
  1551.                     DrawTile(player->position.h, player->position.v);
  1552.                     DrawTile(clickedTile.h, clickedTile.v);
  1553.                     DrawScore();
  1554.                     player->position = clickedTile;
  1555.                     break;
  1556.             } /* case kind */
  1557.         }
  1558.         else
  1559.             switch ( tileArray[clickedTile.h][clickedTile.v] )
  1560.             {
  1561.             case empty:
  1562.             case app:
  1563.             case file:
  1564.             case folder:
  1565.             case fakeWall:
  1566.                 if(tileArray[clickedTile.h][clickedTile.v] == fakeWall)
  1567.                     tileArray[clickedTile.h][clickedTile.v] = empty;
  1568.                     
  1569.                 if(player->standingOnEntityItem && !freedOldPlayerSpot)
  1570.                 {
  1571.                     entityArray[player->position.h][player->position.v] = player->standingOnEntityItem;
  1572.                     player->standingOnEntityItem = nil;
  1573.                 }
  1574.                 else
  1575.                     entityArray[player->position.h][player->position.v] = nil;
  1576.                 
  1577.                 if(entityArray[clickedTile.h][clickedTile.v] != nil)
  1578.                 {
  1579.                     player->standingOnEntityItem = entityArray[clickedTile.h][clickedTile.v];
  1580.                 }
  1581.                 entityArray[clickedTile.h][clickedTile.v] = player;
  1582.     
  1583.                 DrawTile(player->position.h, player->position.v);
  1584.                 DrawTile(clickedTile.h, clickedTile.v);
  1585.                 player->position = clickedTile;
  1586.                 DrawScore();
  1587.                 break;
  1588.             case wall: 
  1589.                 SysBeep(1);
  1590.                 break;
  1591.             case exitPos: 
  1592.                 if(player->standingOnEntityItem && !freedOldPlayerSpot)
  1593.                 {
  1594.                     entityArray[player->position.h][player->position.v] = player->standingOnEntityItem;
  1595.                     player->standingOnEntityItem = nil;
  1596.                 }
  1597.                 else
  1598.                     entityArray[player->position.h][player->position.v] = nil;
  1599.                 entityArray[clickedTile.h][clickedTile.v] = player;
  1600.     
  1601.                 DrawTile(player->position.h, player->position.v);
  1602.                 DrawTile(clickedTile.h, clickedTile.v);
  1603.                 player->position = clickedTile;
  1604.                 
  1605.                 if ( noErr != SndPlay(nil, (SndListHandle)GetNamedResource('snd ', "\pNext level"), false) )
  1606.                     ;
  1607.                 {
  1608.                     long    newParId;
  1609.                     
  1610.                     if(GetParentID(levelVRefNum,levelParId,"\p",&newParId) == noErr)
  1611.                     {
  1612.                         levelParId = newParId;
  1613.                     }
  1614.                 }
  1615.                 CreateLevel();    /* Don't quit - make a new level instead */
  1616.                 break;
  1617.             }; /*case*/
  1618.     }; /*valid move*/
  1619.     
  1620.     ShowAroundPlayer();
  1621.     
  1622. /* Monsters are allowed to move now!*/
  1623.  
  1624.     theEntity = gEntityList;
  1625.     while (theEntity != nil)
  1626.     {
  1627.         if (theEntity->kind == enemyEntity)
  1628.             MoveEnemy(theEntity);
  1629.         theEntity = theEntity->next;
  1630.     }
  1631.  
  1632. } /*MovePlayer*/
  1633.  
  1634. /*
  1635.  *    ScrollProc is the function used in a call to TrackControl for
  1636.  *    scrolling a document window.
  1637.  */
  1638.  
  1639. static pascal void ScrollProc(ControlHandle theControl, short theCode)
  1640.  
  1641. {    long        delta = 0, pageDelta, offset, newLine, realDelta;
  1642.     
  1643.     if (theCode == 0)
  1644.         return;
  1645.  
  1646.     pageDelta = 5;
  1647.     
  1648.     switch(theCode) {
  1649.         case kControlUpButtonPart:
  1650.             delta = -1;
  1651.             break;
  1652.         case kControlDownButtonPart:
  1653.             delta = 1;
  1654.             break;
  1655.         case kControlPageUpPart:
  1656.             delta = -pageDelta;
  1657.             break;
  1658.         case kControlPageDownPart:
  1659.             delta = pageDelta;
  1660.             break;
  1661.     }
  1662.  
  1663.     realDelta = GetControlValue(theControl);
  1664.     
  1665.     SetControlValue(theControl, GetControlValue(theControl) + delta);
  1666.     
  1667.     realDelta = GetControlValue(theControl) - realDelta;        //readjust in case we hit max or min
  1668.     
  1669.     {
  1670.         Rect    clip;
  1671.         RgnHandle saveClip;
  1672.         RgnHandle    invalRgn;
  1673.         
  1674.         SetPort(myWindow);
  1675.         
  1676.         saveClip = NewRgn();
  1677.         invalRgn = NewRgn();
  1678.         
  1679.         GetClip(saveClip);
  1680.         
  1681.         clip = gGameRect;
  1682.         clip.bottom -= kScoreFieldHeight;
  1683.         ClipRect(&clip);
  1684.         
  1685.         if(theControl == scrollV)
  1686.             ScrollRect(&clip,0,-realDelta * kTileSizeV,invalRgn);
  1687.         else
  1688.             ScrollRect(&clip,-realDelta * kTileSizeH,0,invalRgn);
  1689.         
  1690.         InvalRgn(invalRgn);
  1691.         SetClip(saveClip);
  1692.         DisposeRgn(saveClip);    
  1693.         DisposeRgn(invalRgn);
  1694.         DoUpdate();
  1695.     }
  1696. }
  1697.  
  1698. /* Handle mouse downs */
  1699.  
  1700. static void DoMouse(Point clickPoint, long mods)
  1701. {
  1702.     Point clickedTile;
  1703.     short h, v, part;
  1704.     ControlHandle    ctl;
  1705.     
  1706.     SetPort(myWindow);
  1707. /*Convert clickPoint to local coordinates*/
  1708.     GlobalToLocal(&clickPoint);
  1709.  
  1710.     part = FindControl(clickPoint,myWindow,&ctl);
  1711.     if(part && ctl)
  1712.     {
  1713.         short    value, scrollAmt =0;
  1714.         
  1715.         if(part == kControlIndicatorPart)
  1716.         {
  1717.             value = GetControlValue(ctl);
  1718.             part = TrackControl(ctl,clickPoint,nil);
  1719.             if(part)
  1720.             {
  1721.                 scrollAmt = GetControlValue(ctl) - value;
  1722.             }
  1723.         }
  1724.         else
  1725.         {
  1726.             ControlActionUPP    controlAction;
  1727.         
  1728.             controlAction = NewControlActionProc(ScrollProc);
  1729.             TrackControl(ctl, clickPoint, controlAction);
  1730.             DisposeRoutineDescriptor(controlAction);
  1731.         }
  1732.         
  1733. /*        if(scrollAmt)
  1734.         {
  1735.             Rect    clip;
  1736.             RgnHandle saveClip;
  1737.             RgnHandle    invalRgn;
  1738.             
  1739.             SetControlValue(ctl, GetControlValue(ctl) + scrollAmt);
  1740.             saveClip = NewRgn();
  1741.             invalRgn = NewRgn();
  1742.             
  1743.             GetClip(saveClip);
  1744.             
  1745.             clip = gGameRect;
  1746.             clip.bottom -= kScoreFieldHeight;
  1747.             ClipRect(&clip);
  1748.             
  1749.             if(ctl == scrollV)
  1750.                 ScrollRect(&clip,0,32 * kTileSizeV,invalRgn);
  1751.             else
  1752.                 ScrollRect(&clip,32 * kTileSizeH,0,invalRgn);
  1753.             
  1754.             InvalRgn(invalRgn);
  1755.             SetClip(saveClip);
  1756.             DisposeRgn(saveClip);    
  1757.             DisposeRgn(invalRgn);
  1758.         }
  1759. */    }
  1760.     else
  1761.     {
  1762.     /* If the hero is dead, we can't move! */
  1763.         if ( playerHitPoints < 1 )
  1764.         {
  1765.             SysBeep(1);
  1766.             return;
  1767.         };
  1768.  
  1769.     /*Convert it to coordinates in the arrays.*/
  1770.         clickedTile.h = clickPoint.h / kTileSizeH;
  1771.         clickedTile.v = clickPoint.v / kTileSizeV;
  1772.         MovePlayer(clickedTile);
  1773.     }
  1774. } /*DoMouse*/
  1775.  
  1776.  
  1777. /* Empty stub for a background task. */
  1778.  
  1779. static void DoBackground()
  1780. {
  1781. } /*DoBackground*/
  1782.  
  1783.  
  1784. /* Add two points - simplifies the keydown handler */
  1785.  
  1786. static Point AddPoints(Point p1,Point p2)
  1787. {
  1788.     Point dest;
  1789.  
  1790.     dest.h = p1.h + p2.h;
  1791.     dest.v = p1.v + p2.v;
  1792.     return dest;
  1793. }; /*AddPoints*/
  1794.  
  1795.  
  1796. /* Handle key downs */
  1797.  
  1798. static void DoKey(char theKey, long mods)
  1799. {
  1800. /* If the hero is dead, we can't move! */
  1801.     if ( playerHitPoints < 1 )
  1802.         {
  1803.             SysBeep(1);
  1804.             return;
  1805.         };
  1806.  
  1807. /* For now, we use a hard-coded key mapping. */
  1808.     switch ( theKey )
  1809.         {
  1810.         case '^':
  1811.             ShowAll();
  1812.             break;
  1813.         case '$':
  1814.             PayForHealth();
  1815.             break;
  1816.         case 'd':
  1817.         case '6': 
  1818.             MovePlayer(AddPoints(player->position, directionTable[0]));break;
  1819.         case 'e':
  1820.         case '9': 
  1821.             MovePlayer(AddPoints(player->position, directionTable[1]));break;
  1822.         case 'w':
  1823.         case '8': 
  1824.             MovePlayer(AddPoints(player->position, directionTable[2]));break;
  1825.         case 'q':
  1826.         case '7': 
  1827.             MovePlayer(AddPoints(player->position, directionTable[3]));break;
  1828.         case 'a':
  1829.         case '4': 
  1830.             MovePlayer(AddPoints(player->position, directionTable[4]));break;
  1831.         case 'z':
  1832.         case '1': 
  1833.             MovePlayer(AddPoints(player->position, directionTable[5]));break;
  1834.         case 'x':
  1835.         case '2': 
  1836.             MovePlayer(AddPoints(player->position, directionTable[6]));break;
  1837.         case 'c':
  1838.         case '3': 
  1839.             MovePlayer(AddPoints(player->position, directionTable[7]));break;
  1840.         
  1841.         case 'o':
  1842.             OpenItem(player->standingOnEntityItem);
  1843.             break;
  1844.             
  1845.         case 'g':
  1846.             if(player->standingOnEntityItem)
  1847.             {
  1848.                 PickUpItem(player->standingOnEntityItem);
  1849.             }
  1850.             break;
  1851.         case 0x0d:
  1852.             DropItems(player->standingOnEntityItem);
  1853.             break;
  1854.                 
  1855.         case 0x03:
  1856.             if(player->standingOnEntityItem)
  1857.             {
  1858.                 if(player->standingOnEntityItem->kind == directoryEntity)
  1859.                 {
  1860.                     FSSpec    spec;
  1861.                     long    newDirId;
  1862.                     Boolean    isDir;
  1863.                     
  1864.                     spec = player->standingOnEntityItem->spec;
  1865.  
  1866.                     FSpGetDirectoryID(&spec, &newDirId, &isDir);
  1867.                     
  1868.                     if(isDir)    //sanityCheck
  1869.                     {
  1870.                         levelParId = newDirId;
  1871.                         levelVRefNum = spec.vRefNum;
  1872.                         CreateLevel();    /* Don't quit - make a new level instead */
  1873.                         player->standingOnEntityItem = nil;
  1874.                     }
  1875.                 }
  1876.             }    
  1877.             break;
  1878.         default:
  1879.             SysBeep(1);
  1880.     }; /*case*/
  1881. }; /*DoKey*/
  1882.  
  1883.  
  1884. /* Handle selections in the File menu */
  1885.  
  1886. static void DoFileMenu(short item)
  1887. {
  1888.     switch ( item )
  1889.         {
  1890.         case 1: 
  1891.             NewGame();break;
  1892.         case 3: 
  1893.             gDone = true;break;
  1894.     }; /*case*/
  1895. }; /*DoFileMenu*/
  1896.  
  1897.  
  1898. /* The "About" item was selected */
  1899.  
  1900. static void DoAbout()
  1901. {
  1902.     short ignore;
  1903.  
  1904.     ignore = Alert(128, nil);
  1905. }; /*DoAbout*/
  1906.  
  1907.  
  1908. /* Handle update events */
  1909.  
  1910. static void DoUpdate()
  1911. {
  1912.     short h, v;
  1913.  
  1914.     SetPort(myWindow);
  1915.  
  1916.     BeginUpdate(myWindow);
  1917.     
  1918. /*Draw all tiles!*/
  1919.     for ( h = 0 ; h < kArraySizeH ; h++)
  1920.         for ( v = 0 ; v < kArraySizeV ; v++)
  1921.             DrawTile(h, v);
  1922.     
  1923.     DrawScore();
  1924.     
  1925.     EndUpdate(myWindow);
  1926.     DrawGrowIcon(myWindow);
  1927.     DrawControls(myWindow);
  1928. }; /*DoUpdate*/
  1929.  
  1930. static void UpdateInventory()
  1931. {
  1932.     Rect rect;
  1933.     HeldItemPtr    items;
  1934.     
  1935.     BeginUpdate(invWindow);
  1936.     
  1937.     SetPort(invWindow);
  1938.     TextFont(applFont);
  1939.     TextSize(12);
  1940.     
  1941.     rect.top = 5;
  1942.     rect.left = 5;
  1943.     rect.bottom = rect.top + 32;
  1944.     rect.right = rect.left + 32;
  1945.     
  1946.     
  1947.     items = heldItemsList;
  1948.     while(items)
  1949.     {
  1950.         if(items->iconSuite)
  1951.             PlotIconSuite(&rect,atVerticalCenter | atHorizontalCenter, ttNone, items->iconSuite);
  1952.             
  1953.         MoveTo(rect.right + 10, rect.bottom - 10);
  1954.         DrawString(items->spec.name);
  1955.         
  1956.         OffsetRect(&rect, 0,34);
  1957.         items = items->next;
  1958.     }
  1959.     
  1960.     EndUpdate( invWindow);
  1961. }
  1962.  
  1963.  
  1964. /* Handle menu selections */
  1965.  
  1966. static void DoMenuSelection(long mSelect)
  1967. {
  1968.     short menuID;
  1969.     short menuItem;
  1970.     GrafPtr savePort;
  1971.     Str255 name;
  1972.     short ignore;
  1973.  
  1974.     menuID = HiWord(mSelect);
  1975.     menuItem = LoWord(mSelect);
  1976.  
  1977.     switch ( menuID )
  1978.         {
  1979.         case appleID: 
  1980.             if ( menuItem == 1 )
  1981.                 DoAbout();
  1982.             else
  1983.                 {
  1984.                     GetPort(&savePort);
  1985.                     GetMenuItemText(GetMenuHandle(appleID), menuItem, name);
  1986.                     ignore = OpenDeskAcc(name);
  1987.                     SetPort(savePort);
  1988.                 };
  1989.             break;
  1990.         case fileID: 
  1991.             DoFileMenu(menuItem);break;
  1992.         default:
  1993.     ;}; /*case*/
  1994.     HiliteMenu(0);
  1995. }; /*DoMenuSelection*/
  1996.  
  1997.  
  1998. /* Set up menus */
  1999.  
  2000. static void SetupMenus()
  2001. {
  2002.     MenuHandle appleMenu, fileMenu;
  2003.     Str255 tempStr;
  2004.  
  2005.     tempStr[0]=1; tempStr[1] = (char)20;
  2006.     appleMenu = NewMenu(appleID, tempStr); /*Apple menu symbol*/
  2007.     InsertMenu(appleMenu, 0);
  2008.     AppendMenu(appleMenu, "\pAbout Dungeon…;(-");
  2009.     AppendResMenu(appleMenu, 'DRVR');
  2010.  
  2011.     fileMenu = GetMenu(128);
  2012.     InsertMenu(fileMenu, 0);
  2013.     DrawMenuBar ();
  2014.  
  2015. }; /*SetupMenus*/
  2016.  
  2017.  
  2018. /* Main event loop */
  2019.  
  2020. static void MainLoop(void)
  2021. {
  2022. #define    kSleep 5 /*Real programs may modify the sleep time depending on whether or not they are in the front*/
  2023.  
  2024.     EventRecord    theEvent;
  2025.     char    theKey;
  2026.     long    whatSelection;
  2027.     short    whichPart;
  2028.     WindowPtr    whichWindow;
  2029.     Rect    r;
  2030.     Point    diskInitPt = {40,40};
  2031.  
  2032. /*Get the next event with WaitNextEvent.*/
  2033.     if ( WaitNextEvent(everyEvent, &theEvent, kSleep, nil) )
  2034.         switch ( theEvent.what )
  2035.         {
  2036.             case mouseDown: 
  2037. /*We must find out what kind of mouse down this was.*/
  2038.                     whichPart = FindWindow(theEvent.where, &whichWindow);
  2039.                     switch ( whichPart )
  2040.                     {
  2041.                         case inMenuBar:
  2042. /*Click in menu bar. Let the system call MenuSelect track it.*/
  2043.                             whatSelection = MenuSelect(theEvent.where);
  2044.                             DoMenuSelection(whatSelection);    /*Our own routine for handling menu selections*/
  2045.                             break;
  2046.                         case inSysWindow:
  2047. /*Click in some window that isn't ours*/
  2048.                             SystemClick(&theEvent, whichWindow);
  2049.                             break;
  2050.                         case inGoAway:
  2051. /*Click in close box of window. For "desk accessory"-style games, that is a good quit signal*/
  2052.                             if ( (TrackGoAway(whichWindow, theEvent.where)) )
  2053.                                 gDone = true;
  2054.                             break;
  2055.                         case inDrag:
  2056. /*Drag a window*/
  2057.                             if ( (whichWindow != FrontWindow ()) && ((theEvent.modifiers, cmdKey) == 0) )
  2058.                                 SelectWindow(whichWindow);
  2059.                             DragWindow(whichWindow, theEvent.where, &qd.screenBits.bounds);
  2060.                             break;
  2061.                         case inGrow: 
  2062.                             ;  /*Ignored - we don't resize*/
  2063.                             break;
  2064.                         case inContent:
  2065. /*Click in the window.*/
  2066.                             if ( (whichWindow != FrontWindow ()) )
  2067.                                 SelectWindow(whichWindow);
  2068.                             else
  2069.                                 DoMouse(theEvent.where, theEvent.modifiers); /*Go to application-specific mouse down handling*/
  2070.                     }; /*case whichPart*/
  2071.                 break; /*mouseDown*/
  2072.             case keyDown:
  2073.             case autoKey:
  2074.                     if(myWindow)
  2075.                         SetPort(myWindow);
  2076. /*If the command key is pressed, it is a menu selection*/
  2077.                     theKey = (char)(theEvent.message & charCodeMask);
  2078.                     if ( ((theEvent.modifiers & cmdKey) != 0) )
  2079.                         DoMenuSelection(MenuKey(theKey));    /*Our own routine for handling menu selections*/
  2080.                     else
  2081. /*Otherwise, it's a normal key down.*/
  2082.                         DoKey(theKey, theEvent.modifiers);
  2083.                     break;
  2084.             case updateEvt:
  2085. /*Find out what event the update event is for.*/
  2086.                 if ( (WindowPtr)theEvent.message == myWindow )
  2087.                     DoUpdate();
  2088.                     
  2089.                 if( (WindowPtr)theEvent.message == invWindow)
  2090.                     UpdateInventory();
  2091.                 break;
  2092.             case diskEvt:
  2093. /*Handle bad disk insertions*/
  2094.                 if (HiWord(theEvent.message) != noErr)
  2095.                 {
  2096.                     DILoad();
  2097.                     DIBadMount(diskInitPt, theEvent.message);
  2098.                     DIUnload();
  2099.                 }
  2100.                 break;
  2101.             default: /*Other events are ignored*/
  2102.         ;}; /*case*/
  2103.  
  2104. /*For each turn to the event loop, we may to call some "background" process, e.g. animations.*/
  2105.     DoBackground();
  2106. } /*MainLoop*/
  2107.  
  2108.  
  2109. /* Standard inits */
  2110.  
  2111. static void InitToolbox(void) {
  2112.     InitGraf (&qd.thePort);
  2113.     InitFonts ();
  2114.     FlushEvents (everyEvent,0);
  2115.     InitWindows ();
  2116.     InitMenus ();
  2117.     TEInit ();
  2118.     InitDialogs (nil);
  2119.     InitCursor ();
  2120. }
  2121.  
  2122.  
  2123. /* Main program */
  2124.  
  2125. void main(void)
  2126. {
  2127.     InitToolbox();
  2128.     InitDungeon();
  2129.     SetupMenus();
  2130.     NewGame();
  2131. /*Initializations done! Run the game loop until the game ends.*/
  2132.     do
  2133.         {
  2134.         MainLoop();
  2135.     } while (!  gDone);
  2136. } /*Dungeon*/
  2137.  
  2138.  
  2139. OSErr    ReadFSSpecIndex(                        // read an indexed FSSpec entry
  2140.                 SInt16 pVolume,                        // the volume
  2141.                 SInt32 pDirectory,                    // the directory
  2142.                 SInt32 pIndex,                        // the index
  2143.                 FSSpec *rFSSpec,                    // returns the FSSpec
  2144.                 Boolean *rEndOfCatalog)                // returns end of catalog
  2145. {
  2146.     OSErr                rResult;
  2147.     CInfoPBRec            vCatInfo;
  2148.     
  2149.     rFSSpec->vRefNum = pVolume;
  2150.     rFSSpec->parID = pDirectory;
  2151.     rResult = HFS_ReadCatIndex(pVolume, pDirectory, pIndex, &vCatInfo, rFSSpec->name, rEndOfCatalog);
  2152.     
  2153.     return rResult;
  2154. }
  2155.  
  2156. /*
  2157.     _ZeroBlock
  2158. */
  2159. static void _ZeroBlock(Ptr pBlock, long pSize)
  2160. {
  2161.     long x;
  2162.  
  2163.     for(x=0;x<pSize;x++) *pBlock++ = 0;
  2164. }
  2165.  
  2166. typedef union tHFS_PBRecTag
  2167. {
  2168.     CInfoPBRec                        cInfo;
  2169.     HFileInfo                        hFileInfo;
  2170.     DirInfo                            dirInfo;
  2171.     HParamBlockRec                    hParamBlock;
  2172.     HIOParam                        ioParam;
  2173.     HFileParam                        fileParam;
  2174.     HVolumeParam                    volumeParam;
  2175.     AccessParam                        accessParam;
  2176.     ObjParam                        objParam;
  2177.     CopyParam                        copyParam;
  2178.     WDParam                            wdParam;
  2179.     FIDParam                        fidParam;
  2180.     CSParam                            csParam;
  2181.     ForeignPrivParam                foreignPrivParam;
  2182.     ParamBlockRec                    paramBlock;
  2183. }
  2184. tHFS_PBRec;
  2185.  
  2186. // HFS parameter block for general i/o calls
  2187.  
  2188. typedef struct tHFS_ParamBlockTag
  2189. {
  2190.     struct tHFS_ParamBlockTag         *fNext;                // next param block in list
  2191.     tHFS_PBRec                        fParamBlock;        // param block union used by HFS calls
  2192.     Str63                            fName;                // name
  2193.     UInt32                            fRequestTime;        // request time
  2194.     SInt16                            fAccessRefNum;        // access ref num if used in open fork
  2195. }
  2196. tHFS_ParamBlock;
  2197.  
  2198. OSErr    HFS_ReadCatIndex(                            // read an indexed catalog entry
  2199.                 SInt16 pVolume,                        // the volume
  2200.                 SInt32 pDirectory,                    // the directory
  2201.                 SInt32 pIndex,                        // the index
  2202.                 CInfoPBRec *rCatInfo,                // returns the data
  2203.                 unsigned char *rName,                // returns the name
  2204.                 Boolean *rEndOfCatalog)                // returns end of catalog
  2205. {
  2206.     OSErr                rResult = noErr;
  2207.     tHFS_ParamBlock        vParamBlock;
  2208.     
  2209.     // get a parameter block
  2210.     
  2211. //    rResult = HFS_GetParamBlock(NULL, &vParamBlock);
  2212.     _ZeroBlock((Ptr)&vParamBlock, sizeof(tHFS_ParamBlock));
  2213.     vParamBlock.fParamBlock.ioParam.ioNamePtr = vParamBlock.fName;
  2214.  
  2215.     // if this is the system root, get the info for the volume
  2216.     
  2217.     if (!rResult && pVolume == 0)
  2218.     {
  2219.         vParamBlock.fParamBlock.volumeParam.ioVRefNum = 0;
  2220.         vParamBlock.fParamBlock.volumeParam.ioVolIndex = pIndex;
  2221.     
  2222.         // initiate request to get the volume reference number
  2223.         
  2224.         rResult = PBHGetVInfoSync(&vParamBlock.fParamBlock.hParamBlock);
  2225.         
  2226.         // save the results and get another parameter block
  2227.         
  2228.         if (!rResult)
  2229.         {
  2230.             pVolume = vParamBlock.fParamBlock.volumeParam.ioVRefNum;
  2231.             pDirectory = 2;
  2232.             pIndex = -1;
  2233. //            rResult = HFS_GetParamBlock(NULL, &vParamBlock);
  2234.             _ZeroBlock((Ptr)&vParamBlock, sizeof(tHFS_ParamBlock));
  2235.             vParamBlock.fParamBlock.ioParam.ioNamePtr = vParamBlock.fName;
  2236.         }
  2237.     }
  2238.     
  2239.     // get the info for the directory
  2240.     
  2241.     if (!rResult)
  2242.     {
  2243.         vParamBlock.fParamBlock.dirInfo.ioVRefNum = pVolume;
  2244.         vParamBlock.fParamBlock.dirInfo.ioFDirIndex = pIndex;
  2245.         vParamBlock.fParamBlock.dirInfo.ioDrDirID = pDirectory;
  2246.     
  2247.         // initiate catalog info request
  2248.         
  2249.         rResult = PBGetCatInfoSync(&vParamBlock.fParamBlock.cInfo);
  2250.         
  2251.         
  2252.         // return the result
  2253.         
  2254.         if (!rResult)
  2255.         {
  2256.             *rCatInfo = vParamBlock.fParamBlock.cInfo;
  2257.             BlockMoveData(vParamBlock.fName, rName, vParamBlock.fName[0] + 1);
  2258.             *rEndOfCatalog = FALSE;
  2259.         }
  2260.         else // rResult
  2261.         {
  2262.             *rEndOfCatalog = TRUE;
  2263.             rResult = noErr;
  2264.         }    
  2265.     }
  2266.     else // rResult
  2267.         *rEndOfCatalog = TRUE;
  2268.     
  2269.     return rResult;
  2270. }
  2271.  
  2272. static pascal    OSErr    GetFDFlags(short vRefNum,
  2273.                               long dirID,
  2274.                               ConstStr255Param name,
  2275.                               Boolean    *getBits,
  2276.                               unsigned short flagBits)
  2277. {
  2278.     CInfoPBRec pb;
  2279.     Str31 tempName;
  2280.     OSErr error;
  2281.     short realVRefNum;
  2282.     long parID;
  2283.  
  2284.     /* Protection against File Sharing problem */
  2285.     if ( (name == NULL) || (name[0] == 0) )
  2286.     {
  2287.         tempName[0] = 0;
  2288.         pb.hFileInfo.ioNamePtr = tempName;
  2289.         pb.hFileInfo.ioFDirIndex = -1;    /* use ioDirID */
  2290.     }
  2291.     else
  2292.     {
  2293.         pb.hFileInfo.ioNamePtr = (StringPtr)name;
  2294.         pb.hFileInfo.ioFDirIndex = 0;    /* use ioNamePtr and ioDirID */
  2295.     }
  2296.     pb.hFileInfo.ioVRefNum = vRefNum;
  2297.     pb.hFileInfo.ioDirID = dirID;
  2298.     error = PBGetCatInfoSync(&pb);
  2299.     if ( error == noErr )
  2300.     {
  2301.         *getBits = (pb.hFileInfo.ioFlFndrInfo.fdFlags & flagBits) != 0;
  2302.     }
  2303.     
  2304.     return ( error );
  2305. }
  2306.  
  2307. OSErr LaunchApplicationWithDocument(const FSSpec * applicationFSSpecPtr,
  2308.     FSSpecArrayHandle fah)
  2309. {
  2310.     OSErr retCode;
  2311.     LaunchParamBlockRec launchParams;
  2312.     ProcessSerialNumber myPSN;
  2313.     AppleEvent theAppleEvent;
  2314.     AEDesc myAddrDesc, launchParamDesc, docDesc;
  2315.     AEDescList docDescList;
  2316.     AliasHandle docAlias;
  2317.     OSErr        myErr;
  2318.     unsigned short  items, index;
  2319.  
  2320.     AliasHandle        documentAlias;
  2321.     
  2322.  
  2323.     // to simplify cleanup, ensure that handles are nil to start
  2324.     theAppleEvent.dataHandle = nil;
  2325.     launchParamDesc.dataHandle = nil;
  2326.     docDescList.dataHandle = nil;
  2327.     docDesc.dataHandle = nil;
  2328.     docAlias = nil;
  2329.     
  2330.     // the Apple event will need a valid address descriptor (even though its
  2331.     // contents will not matter since we will not be calling AESend) so make 
  2332.     // one using my own serial number
  2333.     
  2334.     (void) GetCurrentProcess(&myPSN);
  2335.     retCode = AECreateDesc(typeProcessSerialNumber, (Ptr) &myPSN,
  2336.         sizeof(ProcessSerialNumber), &myAddrDesc);
  2337.     if (retCode != noErr) goto Bail;
  2338.     
  2339.     // make a descriptor list containing just a descriptor with an
  2340.     // alias to the document
  2341.  
  2342.     retCode = AECreateList(nil, 0, false, &docDescList);
  2343.     if (retCode != noErr) goto Bail;
  2344.  
  2345.     convertfahtoAElist(fah, &docDescList);
  2346.         
  2347.     // now make the 'odoc' AppleEvent descriptor and insert the 
  2348.     // document descriptor list as the direct object
  2349.     
  2350.     retCode = AECreateAppleEvent(kCoreEventClass, kAEOpenDocuments,
  2351.         &myAddrDesc, kAutoGenerateReturnID, kAnyTransactionID,
  2352.         &theAppleEvent);
  2353.     if (retCode != noErr) goto Bail;
  2354.     
  2355.     retCode = AEPutParamDesc(&theAppleEvent, keyDirectObject, &docDescList);
  2356.     if (retCode != noErr) goto Bail;
  2357.     
  2358.     // this Apple event will not be sent but rather will be used
  2359.     // as a parameter to the LaunchApplication call, so coerce it
  2360.     // to the magic type typeAppParamters
  2361.     
  2362.     retCode = AECoerceDesc(&theAppleEvent, typeAppParameters, &launchParamDesc);
  2363.     if (retCode != noErr) goto Bail;
  2364.     
  2365.     // finally, fill in the launch parameter block, including the
  2366.     // Apple event, and make the launch call
  2367.     
  2368.     HLock((Handle) launchParamDesc.dataHandle);
  2369.     launchParams.launchAppParameters =
  2370.         (AppParametersPtr) *(launchParamDesc.dataHandle);
  2371.         
  2372.     launchParams.launchBlockID = extendedBlock;
  2373.     launchParams.launchEPBLength = extendedBlockLen;
  2374.     launchParams.launchFileFlags = launchNoFileFlags;
  2375.     launchParams.launchControlFlags = launchContinue;
  2376.     launchParams.launchAppSpec = (FSSpecPtr) applicationFSSpecPtr;
  2377.  
  2378.     {
  2379.         FInfo    fndrInfo;
  2380.         FSSpec    appFile;
  2381.         Boolean    wasChanged;
  2382.         
  2383.         FSpGetFInfo(applicationFSSpecPtr, &fndrInfo);
  2384.         
  2385.     }
  2386.  
  2387.     retCode = LaunchApplication(&launchParams);
  2388.  
  2389.     if(retCode == -108 && launchParams.launchMinimumSize < launchParams.launchAvailableSize) {
  2390.         launchParams.launchControlFlags = launchContinue | launchUseMinimum;
  2391.         retCode = LaunchApplication(&launchParams);
  2392.     }
  2393.  
  2394. Bail:
  2395.     // dispose of everything that was allocated
  2396.     
  2397.     if (theAppleEvent.dataHandle != nil)     (void) AEDisposeDesc(&theAppleEvent);
  2398.     if (launchParamDesc.dataHandle != nil)   (void) AEDisposeDesc(&launchParamDesc);
  2399.     if (docDescList.dataHandle != nil)       (void) AEDisposeDesc(&docDescList);
  2400.     if (docDesc.dataHandle != nil)           (void) AEDisposeDesc(&docDesc);
  2401.     if (launchParamDesc.dataHandle != nil)   (void) AEDisposeDesc(&launchParamDesc);
  2402.     if (docAlias != nil)
  2403.         DisposeHandle((Handle) docAlias);
  2404.     
  2405.  
  2406.     return retCode;
  2407. }
  2408.  
  2409. OSErr FindAProcess(OSType typeToFind, OSType creatorToFind, ProcessSerialNumberPtr processSN,ProcessInfoRecPtr infoRecToFill)
  2410. {
  2411.     ProcessInfoRec        tempInfo;
  2412.     FSSpec                procSpec;
  2413.     Str31                processName;
  2414.     OSErr                myErr = noErr;
  2415.     
  2416.     processSN->lowLongOfPSN = kNoProcess;
  2417.     processSN->highLongOfPSN = kNoProcess;
  2418.     
  2419.     tempInfo.processInfoLength = sizeof(ProcessInfoRec);
  2420.     tempInfo.processName = (StringPtr)&processName;
  2421.     tempInfo.processAppSpec = &procSpec;
  2422.     
  2423.     while ((tempInfo.processSignature != creatorToFind || tempInfo.processType != typeToFind ||
  2424.                     myErr != noErr))
  2425.     {
  2426.         myErr = GetNextProcess(processSN);
  2427.         if (myErr == noErr) {
  2428.             GetProcessInformation(processSN, &tempInfo);
  2429.         }
  2430.         else {
  2431.             break;
  2432.         }
  2433.     }
  2434.     if(infoRecToFill)
  2435.         *infoRecToFill = tempInfo;
  2436.     return myErr;
  2437. }
  2438.  
  2439. static Boolean    GetIndVRefNum(short which, short *vRefNum, StringPtr    name)
  2440. {
  2441.     OSErr    theErr = noErr;
  2442.     short    index;
  2443.     VolumeParam    vpb;
  2444.     Str255    volName;
  2445.     
  2446.     vpb.ioCompletion = nil;
  2447.     
  2448.     for(index = 1; theErr == noErr; index ++) {
  2449.         vpb.ioVolIndex = index;
  2450.         vpb.ioNamePtr = name;
  2451.         vpb.ioVRefNum = 0;
  2452.         theErr = PBGetVInfoSync((ParmBlkPtr)&vpb);
  2453.         if( (index == which) && (theErr == noErr) ) {
  2454.             *vRefNum = vpb.ioVRefNum;
  2455.             return true;
  2456.         } 
  2457.     }
  2458.     return false;
  2459. }
  2460.  
  2461.  
  2462. /**************************************************************************
  2463.  *
  2464.  *    Procedure PlaySoundAsync
  2465.  *
  2466.  *    If preferences allow, play the click sound asynchronously.
  2467.  *    //sound.h
  2468.  **************************************************************************/
  2469. Handle        gSound = nil;
  2470. SndChannelPtr    gChannel = nil;
  2471. SndCallBackUPP            soundCallbackProc;
  2472. static void SoundCallback(SndChannelPtr chan, SndCommand *cmd)
  2473. {
  2474. //    dprintf("Channel %08lx, cmd->cmd = %d, param1 = %d, param2 = %08lx", chan, cmd->cmd, cmd->param1, cmd->param2);
  2475. }
  2476.  
  2477. void PlaySoundAsync(StringPtr soundName)
  2478. {
  2479.     Handle    sndHandle;
  2480.     OSErr    theErr;
  2481.     
  2482.     if(!soundCallbackProc)
  2483.             soundCallbackProc = NewSndCallBackProc(SoundCallback);
  2484.  
  2485.     if(gChannel) SndDisposeChannel(gChannel, TRUE);
  2486.  
  2487.     gSound = GetNamedResource('snd ', soundName);    
  2488.  
  2489.     if(gSound) {
  2490.         gChannel = nil;
  2491.         theErr = SndNewChannel(&gChannel, 5, initMono, soundCallbackProc);
  2492.         theErr = SndPlay( gChannel, (SndListHandle)gSound, TRUE );        
  2493.     }
  2494. }
  2495.  
  2496.  
  2497. static void SendODOCToProcess(ProcessSerialNumberPtr psn, FSSpecArrayHandle fah)
  2498. {
  2499.     short                errnum;
  2500.     AEDesc                targetaddress;
  2501.     AEDescList            selectionlist;
  2502.     AppleEvent            myae, myreply;
  2503.  
  2504.     if (((errnum = AECreateDesc(typeProcessSerialNumber, psn, sizeof(ProcessSerialNumber), &targetaddress)) == noErr) && 
  2505.         ((errnum = AECreateAppleEvent(kCoreEventClass, kAEOpenDocuments, &targetaddress, kAutoGenerateReturnID, kAnyTransactionID, &myae)) == noErr) && 
  2506.         ((errnum = AEDisposeDesc(&targetaddress)) == noErr) && 
  2507.         ((errnum = AECreateList(nil, 0, FALSE, &selectionlist)) == noErr) && 
  2508.         ((errnum = convertfahtoAElist(fah, &selectionlist)) == noErr) && 
  2509.         ((errnum = AEPutParamDesc(&myae, keyDirectObject, &selectionlist)) == noErr) && 
  2510.         ((errnum = AEDisposeDesc(&selectionlist)) == noErr)) 
  2511.         {
  2512.  
  2513.             if ((errnum == noErr) && 
  2514.                 ((errnum = AESend(&myae, &myreply, kAENoReply, kAENeverInteract, kAEDefaultTimeout, nil, nil)) == noErr) && 
  2515.                 ((errnum = AEDisposeDesc(&myreply)) == noErr)) 
  2516.                 errnum = AEDisposeDesc(&myae);
  2517.         }
  2518.  
  2519. }
  2520.  
  2521.  
  2522. /*-------------*
  2523.  | IsAliasFile |
  2524.  *-------------*/
  2525. static pascal OSErr IsAliasFile(const FSSpec *fileFSSpec,
  2526.                          Boolean *aliasFileFlag,
  2527.                          Boolean *folderFlag)
  2528. /* sets aliasFileFlag if the FSSpec points to an alias file;
  2529.    sets folderFlag if the FSSpec points to a folder */
  2530.    
  2531. {
  2532.     CInfoPBRec myCInfoPBRec;
  2533.     OSErr retCode;
  2534.     
  2535.     if (fileFSSpec == nil || aliasFileFlag == nil || folderFlag == nil)
  2536.         return paramErr;
  2537.     
  2538.     *aliasFileFlag = *folderFlag = false;
  2539.     
  2540.     /* get the item's catalog information */
  2541.     myCInfoPBRec.hFileInfo.ioCompletion = nil;
  2542.     myCInfoPBRec.hFileInfo.ioNamePtr = (StringPtr)&fileFSSpec->name;
  2543.     myCInfoPBRec.hFileInfo.ioVRefNum = fileFSSpec->vRefNum;
  2544.     myCInfoPBRec.hFileInfo.ioDirID = fileFSSpec->parID;
  2545.     myCInfoPBRec.hFileInfo.ioFVersNum = 0;  /* MFS compatibility, see TN #204 */
  2546.     myCInfoPBRec.hFileInfo.ioFDirIndex = 0;
  2547.     
  2548.     retCode = PBGetCatInfoSync(&myCInfoPBRec);
  2549.     
  2550.     /* set aliasFileFlag if the item is not a directory and the
  2551.          aliasFile bit is set */
  2552.          
  2553.     if (retCode == noErr) {
  2554.         /* check directory bit */
  2555.         if ((myCInfoPBRec.hFileInfo.ioFlAttrib & ioDirMask) != 0)
  2556.             *folderFlag = true;
  2557.         
  2558.         /* check isAlias bit */
  2559.         else if ((myCInfoPBRec.hFileInfo.ioFlFndrInfo.fdFlags & 0x8000) != 0)
  2560.             *aliasFileFlag = true;
  2561.     }
  2562.     
  2563.     return retCode;
  2564. }
  2565.  
  2566.  
  2567. /*-----------------------------*
  2568.  | ResolveAliasFileMountOption |
  2569.  *-----------------------------*/
  2570. pascal OSErr ResolveAliasFileMountOption(FSSpec *fileFSSpec,
  2571.                                                  Boolean resolveAliasChains,
  2572.                                                  Boolean *targetIsFolder,
  2573.                                                  Boolean *wasAliased,
  2574.                                                  Boolean mountRemoteVols)
  2575. {
  2576. /* maximum number of aliases to resolve before giving up */
  2577. #define MAXCHAINS 10
  2578.  
  2579.     short myResRefNum;
  2580.     Handle alisHandle;
  2581.     FSSpec initFSSpec;
  2582.     Boolean updateFlag, foundFlag, wasAliasedTemp, specChangedFlag;
  2583.     short chainCount;
  2584.     OSErr retCode;
  2585.     
  2586.     if (fileFSSpec == nil || targetIsFolder == nil || wasAliased == nil)
  2587.         return paramErr;
  2588.     
  2589.     initFSSpec = *fileFSSpec; /* so FSSpec can be restored in case of error */
  2590.     chainCount = MAXCHAINS;   /* circular alias chain protection */
  2591.     myResRefNum = -1;         /* resource file not open */
  2592.     
  2593.     *targetIsFolder = foundFlag = specChangedFlag = false;
  2594.     
  2595.     /* loop through chain of alias files */
  2596.     do {
  2597.         chainCount--;
  2598.         
  2599.         /* check if FSSpec is an alias file or a directory */
  2600.         /* note that targetIsFolder => NOT wasAliased      */
  2601.         
  2602.         retCode = IsAliasFile(fileFSSpec, wasAliased, targetIsFolder);
  2603.         if (retCode != noErr || !(*wasAliased)) break;
  2604.         
  2605.         /* get the resource file reference number */
  2606.         myResRefNum = FSpOpenResFile(fileFSSpec, fsCurPerm);
  2607.         retCode = ResError();
  2608.         if (myResRefNum == -1) break;
  2609.                   
  2610.         /* the first 'alis' resource in the file is the appropriate alias */
  2611.         alisHandle = Get1IndResource(rAliasType, 1);
  2612.         retCode = ResError();
  2613.         if (alisHandle == nil) break;
  2614.         
  2615.         /* load the resource explicitly in case SetResLoad(FALSE) */
  2616.         LoadResource(alisHandle);
  2617.         retCode = ResError();
  2618.         if (retCode != noErr) break;
  2619.  
  2620.         retCode = FollowFinderAlias(fileFSSpec, (AliasHandle) alisHandle, 
  2621.             mountRemoteVols, fileFSSpec, &updateFlag);
  2622.         /* FollowFinderAlias returns nsvErr if volume not mounted */
  2623.         
  2624.         if (retCode == noErr) {
  2625.         
  2626.             if (updateFlag) {
  2627.                 /* the resource in the alias file needs updating */
  2628.                 ChangedResource(alisHandle);
  2629.                 WriteResource(alisHandle);
  2630.             }
  2631.             
  2632.             specChangedFlag = true; /* in case of error, restore file spec */
  2633.             
  2634.             retCode = IsAliasFile(fileFSSpec, &wasAliasedTemp, targetIsFolder);
  2635.             if (retCode == noErr) 
  2636.                 /* we're done unless it was an alias file and we're following a chain */
  2637.                 foundFlag = !(wasAliasedTemp && resolveAliasChains);
  2638.             
  2639.         }
  2640.         
  2641.         CloseResFile(myResRefNum);
  2642.         myResRefNum = -1;
  2643.         
  2644.     } while (retCode == noErr && chainCount > 0 && !foundFlag);
  2645.     
  2646.     /* return file not found error for circular alias chains */
  2647.     if (chainCount == 0 && !foundFlag) retCode = fnfErr;
  2648.  
  2649.     /* if error occurred, close resource file and restore the original FSSpec */
  2650.     if (myResRefNum != -1) CloseResFile(myResRefNum);
  2651.     if (retCode != noErr && specChangedFlag) *fileFSSpec = initFSSpec;
  2652.                 
  2653.     return retCode;
  2654. }
  2655.  
  2656. /*What's left for making a real game of it?*/
  2657. /*- Animations*/
  2658. /*- Several levels*/
  2659. /*- Faster drawing*/
  2660. /*- Asynch sound*/
  2661. /*- More objects, i.e. weapons, monsters, treasures…*/